From 2fcff33bd60bf88488489dc4e7f5b2f5bbcb92bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 19 Feb 2021 13:08:44 +0100 Subject: [PATCH 01/24] [Vulcan/Hebe] Add hebe API login implementation. --- app/build.gradle | 4 + .../java/pl/szczodrzynski/edziennik/App.kt | 21 ++ .../edziennik/config/ConfigSync.kt | 8 + .../edziennik/data/api/Constants.kt | 13 +- .../edziennik/data/api/Errors.kt | 2 + .../edziennik/data/api/LoginMethods.kt | 15 +- .../data/api/edziennik/vulcan/DataVulcan.kt | 50 ++++- .../api/edziennik/vulcan/data/VulcanHebe.kt | 187 ++++++++++++++++++ .../vulcan/firstlogin/VulcanFirstLogin.kt | 123 +++++++++++- .../api/edziennik/vulcan/login/VulcanLogin.kt | 5 + .../edziennik/vulcan/login/VulcanLoginApi.kt | 16 +- .../edziennik/vulcan/login/VulcanLoginHebe.kt | 105 ++++++++++ .../edziennik/ui/modules/login/LoginInfo.kt | 52 +++++ .../res/drawable/login_mode_vulcan_hebe.png | Bin 0 -> 2076 bytes 14 files changed, 578 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt create mode 100644 app/src/main/res/drawable/login_mode_vulcan_hebe.png diff --git a/app/build.gradle b/app/build.gradle index cf1bc55e..710aec8f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -58,6 +58,7 @@ android { dataBinding = true } compileOptions { + coreLibraryDesugaringEnabled true sourceCompatibility '1.8' targetCompatibility '1.8' } @@ -105,6 +106,8 @@ tasks.whenTaskAdded { task -> dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1' + kapt "androidx.room:room-compiler:${versions.room}" debugImplementation "com.amitshekhar.android:debug-db:1.0.5" @@ -181,6 +184,7 @@ dependencies { //implementation "org.redundent:kotlin-xml-builder:1.5.3" implementation "io.github.wulkanowy:signer-android:0.1.1" + implementation 'com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31' implementation "androidx.work:work-runtime-ktx:${versions.work}" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt index 9a2f84d6..88bdc603 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt @@ -294,6 +294,19 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { "Vulcan" ) + val pushVulcanHebeApp = FirebaseApp.initializeApp( + this@App, + FirebaseOptions.Builder() + .setProjectId("dzienniczekplus") + .setStorageBucket("dzienniczekplus.appspot.com") + .setDatabaseUrl("https://dzienniczekplus.firebaseio.com") + .setGcmSenderId("987828170337") + .setApiKey("AIzaSyDW8MUtanHy64_I0oCpY6cOxB3jrvJd_iA") + .setApplicationId("1:987828170337:android:7e16404b9e5deaaa") + .build(), + "VulcanHebe" + ) + try { FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener { instanceIdResult -> val token = instanceIdResult.token @@ -324,6 +337,14 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { config.sync.tokenVulcanList = listOf() } } + FirebaseInstanceId.getInstance(pushVulcanHebeApp).instanceId.addOnSuccessListener { instanceIdResult -> + val token = instanceIdResult.token + d("Firebase", "Got VulcanHebe token: $token") + if (token != config.sync.tokenVulcanHebe) { + config.sync.tokenVulcanHebe = token + config.sync.tokenVulcanHebeList = listOf() + } + } FirebaseMessaging.getInstance().subscribeToTopic(packageName) } catch (e: IllegalStateException) { e.printStackTrace() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigSync.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigSync.kt index 2d7dcf78..068400a1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigSync.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigSync.kt @@ -99,6 +99,10 @@ class ConfigSync(private val config: Config) { var tokenVulcan: String? get() { mTokenVulcan = mTokenVulcan ?: config.values.get("tokenVulcan", null as String?); return mTokenVulcan } set(value) { config.set("tokenVulcan", value); mTokenVulcan = value } + private var mTokenVulcanHebe: String? = null + var tokenVulcanHebe: String? + get() { mTokenVulcanHebe = mTokenVulcanHebe ?: config.values.get("tokenVulcanHebe", null as String?); return mTokenVulcanHebe } + set(value) { config.set("tokenVulcanHebe", value); mTokenVulcanHebe = value } private var mTokenMobidziennikList: List? = null var tokenMobidziennikList: List @@ -112,6 +116,10 @@ class ConfigSync(private val config: Config) { var tokenVulcanList: List get() { mTokenVulcanList = mTokenVulcanList ?: config.values.getIntList("tokenVulcanList", listOf()); return mTokenVulcanList ?: listOf() } set(value) { config.set("tokenVulcanList", value); mTokenVulcanList = value } + private var mTokenVulcanHebeList: List? = null + var tokenVulcanHebeList: List + get() { mTokenVulcanHebeList = mTokenVulcanHebeList ?: config.values.getIntList("tokenVulcanHebeList", listOf()); return mTokenVulcanHebeList ?: listOf() } + set(value) { config.set("tokenVulcanHebeList", value); mTokenVulcanHebeList = value } private var mRegisterAvailability: Map? = null var registerAvailability: Map diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index 5bc08159..016d0eb4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -95,7 +95,16 @@ const val VULCAN_API_APP_NAME = "VULCAN-Android-ModulUcznia" const val VULCAN_API_APP_VERSION = "20.5.1.470" const val VULCAN_API_PASSWORD = "CE75EA598C7743AD9B0B7328DED85B06" const val VULCAN_API_PASSWORD_FAKELOG = "012345678901234567890123456789AB" -val VULCAN_API_DEVICE_NAME = "Szkolny.eu ${Build.MODEL}" +const val VULCAN_HEBE_USER_AGENT = "Dart/2.10 (dart:io)" +const val VULCAN_HEBE_APP_NAME = "DzienniczekPlus 2.0" +const val VULCAN_HEBE_APP_VERSION = "21.02.09 (G)" +private const val VULCAN_API_DEVICE_NAME_PREFIX = "Szkolny.eu " +private const val VULCAN_API_DEVICE_NAME_SUFFIX = " - nie usuwać" +val VULCAN_API_DEVICE_NAME by lazy { + val base = "$VULCAN_API_DEVICE_NAME_PREFIX${Build.MODEL}" + val baseMaxLength = 50 - VULCAN_API_DEVICE_NAME_SUFFIX.length + base.take(baseMaxLength) + VULCAN_API_DEVICE_NAME_SUFFIX +} const val VULCAN_API_ENDPOINT_CERTIFICATE = "mobile-api/Uczen.v3.UczenStart/Certyfikat" const val VULCAN_API_ENDPOINT_STUDENT_LIST = "mobile-api/Uczen.v3.UczenStart/ListaUczniow" @@ -116,6 +125,8 @@ const val VULCAN_API_ENDPOINT_MESSAGES_ATTACHMENTS = "mobile-api/Uczen.v3.Uczen/ const val VULCAN_API_ENDPOINT_HOMEWORK_ATTACHMENTS = "mobile-api/Uczen.v3.Uczen/ZadaniaDomoweZalacznik" const val VULCAN_WEB_ENDPOINT_LUCKY_NUMBER = "Start.mvc/GetKidsLuckyNumbers" const val VULCAN_WEB_ENDPOINT_REGISTER_DEVICE = "RejestracjaUrzadzeniaToken.mvc/Get" +const val VULCAN_HEBE_ENDPOINT_REGISTER_NEW = "api/mobile/register/new" +const val VULCAN_HEBE_ENDPOINT_MAIN = "api/mobile/register/hebe" const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt index 8301f62f..c7a47e24 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt @@ -170,6 +170,7 @@ const val ERROR_VULCAN_WEB_LOGGED_OUT = 350 const val ERROR_VULCAN_WEB_CERTIFICATE_POST_FAILED = 351 const val ERROR_VULCAN_WEB_GRADUATE_ACCOUNT = 352 const val ERROR_VULCAN_WEB_NO_SCHOOLS = 353 +const val ERROR_VULCAN_HEBE_OTHER = 354 const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN = 401 const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME = 402 @@ -229,5 +230,6 @@ const val ERROR_ONEDRIVE_DOWNLOAD = 930 const val EXCEPTION_VULCAN_WEB_LOGIN = 931 const val EXCEPTION_VULCAN_WEB_REQUEST = 932 const val EXCEPTION_PODLASIE_API_REQUEST = 940 +const val EXCEPTION_VULCAN_HEBE_REQUEST = 950 const val LOGIN_NO_ARGUMENTS = 1201 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt index 24444a58..269cf9ed 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt @@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLogi import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginApi import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginWeb import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginApi +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginHebe import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginWebMain import pl.szczodrzynski.edziennik.data.api.models.LoginMethod @@ -98,11 +99,13 @@ val mobidziennikLoginMethods = listOf( const val LOGIN_TYPE_VULCAN = 4 const val LOGIN_MODE_VULCAN_API = 0 const val LOGIN_MODE_VULCAN_WEB = 1 +const val LOGIN_MODE_VULCAN_HEBE = 2 const val LOGIN_METHOD_VULCAN_WEB_MAIN = 100 const val LOGIN_METHOD_VULCAN_WEB_NEW = 200 const val LOGIN_METHOD_VULCAN_WEB_OLD = 300 const val LOGIN_METHOD_VULCAN_WEB_MESSAGES = 400 const val LOGIN_METHOD_VULCAN_API = 500 +const val LOGIN_METHOD_VULCAN_HEBE = 600 val vulcanLoginMethods = listOf( LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_MAIN, VulcanLoginWebMain::class.java) .withIsPossible { _, loginStore -> loginStore.hasLoginData("webHost") } @@ -117,9 +120,19 @@ val vulcanLoginMethods = listOf( .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN },*/ LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_API, VulcanLoginApi::class.java) - .withIsPossible { _, _ -> true } + .withIsPossible { _, loginStore -> + loginStore.mode == LOGIN_MODE_VULCAN_API + } .withRequiredLoginMethod { _, loginStore -> if (loginStore.mode == LOGIN_MODE_VULCAN_WEB) LOGIN_METHOD_VULCAN_WEB_MAIN else LOGIN_METHOD_NOT_NEEDED + }, + + LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_HEBE, VulcanLoginHebe::class.java) + .withIsPossible { _, loginStore -> + loginStore.mode == LOGIN_MODE_VULCAN_HEBE + } + .withRequiredLoginMethod { _, loginStore -> + if (loginStore.mode == LOGIN_MODE_VULCAN_WEB) LOGIN_METHOD_VULCAN_WEB_MAIN else LOGIN_METHOD_NOT_NEEDED } ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt index 882a2fa4..d494ec3d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt @@ -4,16 +4,15 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan -import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.currentTimeUnix +import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_API +import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_HEBE +import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_WEB_MAIN import pl.szczodrzynski.edziennik.data.api.models.Data import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Team -import pl.szczodrzynski.edziennik.isNotNullNorEmpty import pl.szczodrzynski.edziennik.utils.Utils -import pl.szczodrzynski.edziennik.values class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) { @@ -26,12 +25,21 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app && apiFingerprint[symbol].isNotNullNorEmpty() && apiPrivateKey[symbol].isNotNullNorEmpty() && symbol.isNotNullNorEmpty() + fun isHebeLoginValid() = hebePublicKey.isNotNullNorEmpty() + && hebePrivateKey.isNotNullNorEmpty() + && symbol.isNotNullNorEmpty() override fun satisfyLoginMethods() { loginMethods.clear() + if (isWebMainLoginValid()) { + loginMethods += LOGIN_METHOD_VULCAN_WEB_MAIN + } if (isApiLoginValid()) { loginMethods += LOGIN_METHOD_VULCAN_API } + if (isHebeLoginValid()) { + loginMethods += LOGIN_METHOD_VULCAN_HEBE + } } init { @@ -55,6 +63,17 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app override fun generateUserCode() = "$schoolCode:$studentId" + fun buildDeviceId(): String { + val deviceId = app.deviceId.padStart(16, '0') + val loginStoreId = loginStore.id.toString(16).padStart(4, '0') + val symbol = symbol?.crc16()?.toString(16)?.take(2) ?: "00" + return deviceId.substring(0..7) + + "-" + deviceId.substring(8..11) + + "-" + deviceId.substring(12..15) + + "-" + loginStoreId + + "-" + symbol + "6f72616e7a" + } + /** * A UONET+ client symbol. * @@ -203,6 +222,27 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app get() { mApiPrivateKey = mApiPrivateKey ?: loginStore.getLoginData("apiPrivateKey", null)?.let { app.gson.fromJson(it, field.toMutableMap()::class.java) }; return mApiPrivateKey ?: mapOf() } set(value) { loginStore.putLoginData("apiPrivateKey", app.gson.toJson(value)); mApiPrivateKey = value } + /* _ _ _ _____ _____ + | | | | | | /\ | __ \_ _| + | |__| | ___| |__ ___ / \ | |__) || | + | __ |/ _ \ '_ \ / _ \ / /\ \ | ___/ | | + | | | | __/ |_) | __/ / ____ \| | _| |_ + |_| |_|\___|_.__/ \___| /_/ \_\_| |____*/ + private var mHebePublicKey: String? = null + var hebePublicKey: String? + get() { mHebePublicKey = mHebePublicKey ?: loginStore.getLoginData("hebePublicKey", null); return mHebePublicKey } + set(value) { loginStore.putLoginData("hebePublicKey", value); mHebePublicKey = value } + + private var mHebePrivateKey: String? = null + var hebePrivateKey: String? + get() { mHebePrivateKey = mHebePrivateKey ?: loginStore.getLoginData("hebePrivateKey", null); return mHebePrivateKey } + set(value) { loginStore.putLoginData("hebePrivateKey", value); mHebePrivateKey = value } + + private var mHebePublicHash: String? = null + var hebePublicHash: String? + get() { mHebePublicHash = mHebePublicHash ?: loginStore.getLoginData("hebePublicHash", null); return mHebePublicHash } + set(value) { loginStore.putLoginData("hebePublicHash", value); mHebePublicHash = value } + val apiUrl: String? get() { val url = when (apiToken[symbol]?.substring(0, 3)) { @@ -227,7 +267,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app return if (url != null) "$url/$symbol/" else loginStore.getLoginData("apiUrl", null) } - val fullApiUrl: String? + val fullApiUrl: String get() { return "$apiUrl$schoolSymbol/" } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt new file mode 100644 index 00000000..cd8a9b77 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt @@ -0,0 +1,187 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data + +import android.os.Build +import com.google.gson.JsonArray +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 io.github.wulkanowy.signer.hebe.getSignatureHeaders +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.data.api.* +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.utils.Utils.d +import java.net.HttpURLConnection +import java.net.URLEncoder +import java.time.ZoneId +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import java.util.* + +open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { + companion object { + const val TAG = "VulcanHebe" + } + + val profileId + get() = data.profile?.id ?: -1 + + val profile + get() = data.profile + + inline fun apiRequest( + tag: String, + endpoint: String, + method: Int = GET, + payload: JsonObject? = null, + baseUrl: Boolean = false, + crossinline onSuccess: (json: T, response: Response?) -> Unit + ) { + val url = "${if (baseUrl) data.apiUrl else data.fullApiUrl}$endpoint" + + d(tag, "Request: Vulcan/Hebe - $url") + + val privateKey = data.hebePrivateKey + val publicHash = data.hebePublicHash + + if (privateKey == null || publicHash == null) { + data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING)) + return + } + + val timestamp = ZonedDateTime.now(ZoneId.of("GMT")) + val timestampMillis = timestamp.toInstant().toEpochMilli() + val timestampIso = timestamp.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")) + + val finalPayload = if (payload != null) { + JsonObject( + "AppName" to VULCAN_HEBE_APP_NAME, + "AppVersion" to VULCAN_HEBE_APP_VERSION, + "CertificateId" to publicHash, + "Envelope" to payload, + "FirebaseToken" to data.app.config.sync.tokenVulcanHebe, + "API" to 1, + "RequestId" to UUID.randomUUID().toString(), + "Timestamp" to timestampMillis, + "TimestampFormatted" to timestampIso + ) + } else null + val jsonString = finalPayload?.toString() + + val headers = getSignatureHeaders( + publicHash, + privateKey, + jsonString, + endpoint, + timestamp + ) + + val callback = object : JsonCallbackHandler() { + override fun onSuccess(json: JsonObject?, response: Response?) { + if (json == null) { + data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY) + .withResponse(response) + ) + return + } + + val status = json.getJsonObject("Status") + if (status?.getInt("Code") != 0) { + data.error(ApiError(tag, ERROR_VULCAN_HEBE_OTHER) + .withResponse(response) + .withApiResponse(json.toString())) + } + + val envelope = when (T::class.java) { + JsonObject::class.java -> json.getJsonObject("Envelope") + JsonArray::class.java -> json.getJsonArray("Envelope") + else -> { + data.error(ApiError(tag, ERROR_RESPONSE_EMPTY) + .withResponse(response) + .withApiResponse(json) + ) + return + } + } + + try { + onSuccess(envelope as T, response) + } catch (e: Exception) { + data.error(ApiError(tag, EXCEPTION_VULCAN_HEBE_REQUEST) + .withResponse(response) + .withThrowable(e) + .withApiResponse(json) + ) + } + } + + override fun onFailure(response: Response?, throwable: Throwable?) { + data.error(ApiError(tag, ERROR_REQUEST_FAILURE) + .withResponse(response) + .withThrowable(throwable) + ) + } + } + + Request.builder() + .url(url) + .userAgent(VULCAN_HEBE_USER_AGENT) + .addHeader("vOS", "Android") + .addHeader("vDeviceModel", Build.MODEL) + .addHeader("vAPI", "1") + .apply { + headers.forEach { + addHeader(it.key, it.value) + } + when (method) { + GET -> get() + POST -> { + post() + setTextBody(jsonString, MediaTypeUtils.APPLICATION_JSON) + } + } + } + .allowErrorCode(HttpURLConnection.HTTP_BAD_REQUEST) + .allowErrorCode(HttpURLConnection.HTTP_FORBIDDEN) + .allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED) + .allowErrorCode(HttpURLConnection.HTTP_UNAVAILABLE) + .callback(callback) + .build() + .enqueue() + } + + inline fun apiGet( + tag: String, + endpoint: String, + query: Map = mapOf(), + baseUrl: Boolean = false, + crossinline onSuccess: (json: T, response: Response?) -> Unit + ) { + val queryPath = query.map { it.key + "=" + URLEncoder.encode(it.value, "UTF-8") }.join("&") + apiRequest( + tag, + if (query.isNotEmpty()) "$endpoint?$queryPath" else endpoint, + baseUrl = baseUrl, + onSuccess = onSuccess + ) + } + + inline fun apiPost( + tag: String, + endpoint: String, + payload: JsonObject, + baseUrl: Boolean = false, + crossinline onSuccess: (json: T, response: Response?) -> Unit + ) { + apiRequest( + tag, + endpoint, + method = POST, + payload, + baseUrl = baseUrl, + onSuccess = onSuccess + ) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt index ed541c69..b670b12a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt @@ -4,14 +4,17 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.firstlogin +import com.google.gson.JsonArray import org.greenrobot.eventbus.EventBus import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanWebMain import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.CufsCertificate import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginApi +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginHebe import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginWebMain import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -25,6 +28,7 @@ class VulcanFirstLogin(val data: DataVulcan, val onSuccess: () -> Unit) { private val api = VulcanApi(data, null) private val web = VulcanWebMain(data, null) + private val hebe = VulcanHebe(data, null) private val profileList = mutableListOf() private val loginStoreId = data.loginStore.id private var firstProfileId = loginStoreId @@ -50,12 +54,18 @@ class VulcanFirstLogin(val data: DataVulcan, val onSuccess: () -> Unit) { checkSymbol(certificate) } } - else { + else if (data.loginStore.mode == LOGIN_MODE_VULCAN_API) { registerDevice { EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore)) onSuccess() } } + else { + registerDeviceHebe { + EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore)) + onSuccess() + } + } } private fun checkSymbol(certificate: CufsCertificate) { @@ -103,7 +113,7 @@ class VulcanFirstLogin(val data: DataVulcan, val onSuccess: () -> Unit) { data.apiPin = data.apiPin.toMutableMap().also { it[symbol] = json.getString("PIN") } - registerDevice(onSuccess) + registerDeviceHebe(onSuccess) } } } @@ -197,4 +207,113 @@ class VulcanFirstLogin(val data: DataVulcan, val onSuccess: () -> Unit) { } } } + + private fun registerDeviceHebe(onSuccess: () -> Unit) { + VulcanLoginHebe(data) { + hebe.apiGet( + TAG, + VULCAN_HEBE_ENDPOINT_MAIN, + query = mapOf("lastSyncDate" to "null"), + baseUrl = true + ) { students: JsonArray, _ -> + if (students.isEmpty()) { + EventBus.getDefault().postSticky(FirstLoginFinishedEvent(listOf(), data.loginStore)) + onSuccess() + return@apiGet + } + + students.forEach { studentEl -> + val student = studentEl.asJsonObject + + val unit = student.getJsonObject("Unit") + //val constituentUnit = student.getJsonObject("ConstituentUnit") + val pupil = student.getJsonObject("Pupil") + val login = student.getJsonObject("Login") + val periods = student.getJsonArray("Periods")?.map { + it.asJsonObject + } ?: listOf() + + val period = periods.firstOrNull { + it.getBoolean("Current", false) + } ?: return@forEach + + val periodLevel = period.getInt("Level") ?: return@forEach + val semester1 = periods.firstOrNull { + it.getInt("Level") == periodLevel && it.getInt("Number") == 1 + } + val semester2 = periods.firstOrNull { + it.getInt("Level") == periodLevel && it.getInt("Number") == 2 + } + + val schoolSymbol = unit.getString("Symbol") ?: return@forEach + val schoolShort = unit.getString("Short") ?: return@forEach + val schoolCode = "${data.symbol}_$schoolSymbol" + val studentId = pupil.getInt("Id") ?: return@forEach + val studentLoginId = login.getInt("Id") ?: return@forEach + //val studentClassId = student.getInt("IdOddzial") ?: return@forEach + val studentClassName = student.getString("ClassDisplay") ?: return@forEach + val studentFirstName = pupil.getString("FirstName") ?: "" + val studentLastName = pupil.getString("Surname") ?: "" + val studentNameLong = "$studentFirstName $studentLastName".fixName() + val studentNameShort = "$studentFirstName ${studentLastName[0]}.".fixName() + val userLogin = login.getString("Value") ?: "" + + val studentSemesterId = period.getInt("Id") ?: return@forEach + val studentSemesterNumber = period.getInt("Number") ?: return@forEach + + val isParent = login.getString("LoginRole").equals("opiekun", ignoreCase = true) + val accountName = if (isParent) + login.getString("DisplayName")?.fixName() + else null + + val dateSemester1Start = semester1 + ?.getJsonObject("Start") + ?.getString("Date") + ?.let { Date.fromY_m_d(it) } + val dateSemester2Start = semester2 + ?.getJsonObject("Start") + ?.getString("Date") + ?.let { Date.fromY_m_d(it) } + val dateYearEnd = semester2 + ?.getJsonObject("End") + ?.getString("Date") + ?.let { Date.fromY_m_d(it) } + + val profile = Profile( + firstProfileId++, + loginStoreId, + LOGIN_TYPE_VULCAN, + studentNameLong, + userLogin, + studentNameLong, + studentNameShort, + accountName + ).apply { + this.studentClassName = studentClassName + studentData["symbol"] = data.symbol + + studentData["studentId"] = studentId + studentData["studentLoginId"] = studentLoginId + studentData["studentSemesterId"] = studentSemesterId + studentData["studentSemesterNumber"] = studentSemesterNumber + studentData["semester1Id"] = semester1?.getInt("Id") ?: 0 + studentData["semester2Id"] = semester2?.getInt("Id") ?: 0 + studentData["schoolSymbol"] = schoolSymbol + studentData["schoolShort"] = schoolShort + studentData["schoolName"] = schoolCode + } + dateSemester1Start?.let { + profile.dateSemester1Start = it + profile.studentSchoolYearStart = it.year + } + dateSemester2Start?.let { profile.dateSemester2Start = it } + dateYearEnd?.let { profile.dateYearEnd = it } + + profileList.add(profile) + } + + onSuccess() + } + } + } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLogin.kt index 45c0153d..b92dea88 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLogin.kt @@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_API +import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_HEBE import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_WEB_MAIN import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.utils.Utils @@ -54,6 +55,10 @@ class VulcanLogin(val data: DataVulcan, val onSuccess: () -> Unit) { data.startProgress(R.string.edziennik_progress_login_vulcan_api) VulcanLoginApi(data) { onSuccess(loginMethodId) } } + LOGIN_METHOD_VULCAN_HEBE -> { + data.startProgress(R.string.edziennik_progress_login_vulcan_api) + VulcanLoginHebe(data) { onSuccess(loginMethodId) } + } } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginApi.kt index ec84cd05..def1d7e3 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginApi.kt @@ -191,18 +191,6 @@ class VulcanLoginApi(val data: DataVulcan, val onSuccess: () -> Unit) { } } - val deviceId = data.app.deviceId.padStart(16, '0') - val loginStoreId = data.loginStore.id.toString(16).padStart(4, '0') - val symbol = data.symbol?.crc16()?.toString(16)?.take(2) ?: "00" - val uuid = - deviceId.substring(0..7) + - "-" + deviceId.substring(8..11) + - "-" + deviceId.substring(12..15) + - "-" + loginStoreId + - "-" + symbol + "6f72616e7a" - - val deviceNameSuffix = " - nie usuwać" - val szkolnyApi = SzkolnyApi(data.app) val firebaseToken = szkolnyApi.runCatching({ getFirebaseToken("vulcan") @@ -216,8 +204,8 @@ class VulcanLoginApi(val data: DataVulcan, val onSuccess: () -> Unit) { .addHeader("RequestMobileType", "RegisterDevice") .addParameter("PIN", data.apiPin[data.symbol]) .addParameter("TokenKey", data.apiToken[data.symbol]) - .addParameter("DeviceId", uuid) - .addParameter("DeviceName", VULCAN_API_DEVICE_NAME.take(50 - deviceNameSuffix.length) + deviceNameSuffix) + .addParameter("DeviceId", data.buildDeviceId()) + .addParameter("DeviceName", VULCAN_API_DEVICE_NAME) .addParameter("DeviceNameUser", "") .addParameter("DeviceDescription", "") .addParameter("DeviceSystemType", "Android") diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt new file mode 100644 index 00000000..b2c27454 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt @@ -0,0 +1,105 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login + +import com.google.gson.JsonObject +import io.github.wulkanowy.signer.hebe.generateKeyPair +import pl.szczodrzynski.edziennik.JsonObject +import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_DATA_MISSING +import pl.szczodrzynski.edziennik.data.api.VULCAN_API_DEVICE_NAME +import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_REGISTER_NEW +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe +import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi +import pl.szczodrzynski.edziennik.getString +import pl.szczodrzynski.edziennik.isNotNullNorEmpty + +class VulcanLoginHebe(val data: DataVulcan, val onSuccess: () -> Unit) { + companion object { + private const val TAG = "VulcanLoginHebe" + } + + init { run { + // i'm sure this does something useful + // not quite sure what, though + if (data.studentSemesterNumber == 1 && data.semester1Id == 0) + data.semester1Id = data.studentSemesterNumber + if (data.studentSemesterNumber == 2 && data.semester2Id == 0) + data.semester2Id = data.studentSemesterNumber + + copyFromLoginStore() + + if (data.profile != null && data.isApiLoginValid()) { + onSuccess() + } + else { + if (data.symbol.isNotNullNorEmpty() && data.apiToken[data.symbol].isNotNullNorEmpty() && data.apiPin[data.symbol].isNotNullNorEmpty()) { + loginWithToken() + } + else { + data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING)) + } + } + }} + + private fun copyFromLoginStore() { + data.loginStore.data.apply { + // map form inputs to the symbol + if (has("symbol")) { + data.symbol = getString("symbol") + remove("symbol") + } + if (has("deviceToken")) { + data.apiToken = data.apiToken.toMutableMap().also { + it[data.symbol] = getString("deviceToken") + } + remove("deviceToken") + } + if (has("devicePin")) { + data.apiPin = data.apiPin.toMutableMap().also { + it[data.symbol] = getString("devicePin") + } + remove("devicePin") + } + } + } + + private fun loginWithToken() { + val szkolnyApi = SzkolnyApi(data.app) + val hebe = VulcanHebe(data, null) + + if (data.hebePublicKey == null || data.hebePrivateKey == null || data.hebePublicHash == null) { + val (publicPem, privatePem, publicHash) = generateKeyPair() + data.hebePublicKey = publicPem + data.hebePrivateKey = privatePem + data.hebePublicHash = publicHash + } + + szkolnyApi.runCatching({ + data.app.config.sync.tokenVulcanHebe = getFirebaseToken("vulcan") + }, onError = { + // screw errors + }) + + hebe.apiPost( + TAG, + VULCAN_HEBE_ENDPOINT_REGISTER_NEW, + payload = JsonObject( + "OS" to "Android", + "PIN" to data.apiPin[data.symbol], + "Certificate" to data.hebePublicKey, + "CertificateType" to "RSA_PEM", + "DeviceModel" to VULCAN_API_DEVICE_NAME, + "SecurityToken" to data.apiToken[data.symbol], + "SelfIdentifier" to data.buildDeviceId(), + "CertificateThumbprint" to data.hebePublicHash + ), + baseUrl = true + ) { _: JsonObject, _ -> + data.apiToken = data.apiToken.toMutableMap().also { + it[data.symbol] = it[data.symbol]?.substring(0, 3) + } + data.loginStore.removeLoginData("apiPin") + onSuccess() + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt index 2b3acd68..0ed90bdf 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt @@ -182,6 +182,58 @@ object LoginInfo { ERROR_LOGIN_VULCAN_EXPIRED_TOKEN to R.string.login_error_expired_token ) ), + Mode( + loginMode = LOGIN_MODE_VULCAN_HEBE, + name = R.string.login_mode_vulcan_api, + icon = R.drawable.login_mode_vulcan_hebe, + hintText = R.string.login_mode_vulcan_api_hint, + guideText = R.string.login_mode_vulcan_api_guide, + isTesting = true, + credentials = listOf( + FormField( + keyName = "deviceToken", + name = R.string.login_hint_token, + icon = CommunityMaterial.Icon.cmd_code_braces, + emptyText = R.string.login_error_no_token, + invalidText = R.string.login_error_incorrect_token, + errorCodes = mapOf( + ERROR_LOGIN_VULCAN_INVALID_TOKEN to R.string.login_error_incorrect_token + ), + isRequired = true, + validationRegex = "[A-Z0-9]{5,12}", + caseMode = FormField.CaseMode.UPPER_CASE + ), + FormField( + keyName = "symbol", + name = R.string.login_hint_symbol, + icon = CommunityMaterial.Icon2.cmd_school, + emptyText = R.string.login_error_no_symbol, + invalidText = R.string.login_error_incorrect_symbol, + errorCodes = mapOf( + ERROR_LOGIN_VULCAN_INVALID_SYMBOL to R.string.login_error_incorrect_symbol + ), + isRequired = true, + validationRegex = "[a-z0-9_-]+", + caseMode = FormField.CaseMode.LOWER_CASE + ), + FormField( + keyName = "devicePin", + name = R.string.login_hint_pin, + icon = CommunityMaterial.Icon2.cmd_lock, + emptyText = R.string.login_error_no_pin, + invalidText = R.string.login_error_incorrect_pin, + errorCodes = mapOf( + ERROR_LOGIN_VULCAN_INVALID_PIN to R.string.login_error_incorrect_pin + ), + isRequired = true, + validationRegex = "[0-9]+", + caseMode = FormField.CaseMode.LOWER_CASE + ) + ), + errorCodes = mapOf( + ERROR_LOGIN_VULCAN_EXPIRED_TOKEN to R.string.login_error_expired_token + ) + ), Mode( loginMode = LOGIN_MODE_VULCAN_WEB, name = R.string.login_mode_vulcan_web, diff --git a/app/src/main/res/drawable/login_mode_vulcan_hebe.png b/app/src/main/res/drawable/login_mode_vulcan_hebe.png new file mode 100644 index 0000000000000000000000000000000000000000..bea96dc7807662edc11070a02e11ef4ad1f162ff GIT binary patch literal 2076 zcmV+%2;=vOP)%+h_J{S7F5DEX#^)Uh(GvH?M@I^vrLG$Zx`ZhX+oU+ zTlBaiuq4ho&1nO&W#o{^fpOMJLafb-P6|#{2Z4|sqD{ql2H!A=!~?k?JVbs}OyB zEs>qPhvel}G6zW>UgQvB%Rz`bknCo&AAmxHSj*R*fbg3gLHZRb-v>B6Fto7^D#Qau zgJL075LszR2oU<+vp??=ZB+p%RERG9fxMB!1t$+Fo4_e#;8aqd7VR}Gm2`2vausmcXt`o8@m093fw1*nh!I!y9T zDN>maaP$D91WE}K4Jh+~Mu2ij{*m&InZ&e|klC=R9|bVpKq*1e91t(GDw);le!@|L zB;}-Py#VEV2`zfHQU@n&<}rACV<$YfxK$@e>?MHafaq0=4K2Hu)yg-c9#1?Def@*5 zZFjd$o>a#|(i#x!J-+0fM!x|4J1_{Jec!EPxY7AYb3m;3R5RXFKcbwY51>Xbp{6;Y z5}Djn3*%pCfQ{c=f-PxXuqpKtQkUQQ6or<-HROnA9+PtxjkabjmK+=VaGufX;__ec1> z@f`46l2)Hm$VIvUs^9>sN0aFgCv~L!20WN>Y!t6~+=bs8&%qN=<7fb)FAUw2vjJ!r zkd%Mim-fH_#6r>>5I_GIfV={7Ui%n;L_lLR6thE0nJ<00q<|_g!P|a6wh(5 z&jD|4I1jIXbQWg3cGB>mJ-_tGer3Q{#{c^yoxJWGWMo}~g9U$y=fHbHnR$PTuPtBu zyRpnmdS+pZc#a#r1A&@@^u16F0zejB0pUIASrefa`gvLRedkq{Chx^@UdeUPzmRjk2B2t z0kr6?)9~)5PF2Fk`VVN-Htl)0eVlhxlUBEl;T*&RWY_b?A-kH{#wehU(Y|q5z^UqR z-aMS2d{UfLXV*R0bEpTtJ9vMD-y6>X&t-mc2M11_p0}Rq;sy7jsfYy)aOGOxn7J=@ zO}F5;&byGXtW9O5*{BszWs%ZfTtrpO z4K>e_Ur$JQGwjx#0TI$evs_!NJV03UlTX3L?mn>Cd&L3=|7sQMICVi%ouV#)e5r7? z$rf?WT-pjf*ZaX-b5q=dri~N<-EqL?9qxdzhrRL1dGU8UGOwzvc4gsM^aPZ})JRLK znlhy2YtKMa`)!C`(&`a<6J|F-ZSyTy_3>E`4;hD+@2$HoLuvI*FJRc!s+Os|uOf4_ zkPlW@K)fpZavy7@l?usy4Iw$NspGUIuy9KB0F(`$kPef4qy)*X0#t(vFtyB5Ze_ws zf>Wf|GM}XY$?Rt{OTC|c8*)u8-kMo>a0>JQRLB8DLy~K1;dzstYCiF&^GB)6hhD}j ziAR@_Ihjb_%-73tn*3O=F_XENh}YzkxoWnG z(Y+dUGmAG!1x#MDFuBPp1IxxhV`Wo-LU;6(F(Gw?T%Kf;=ha&EY83C~w?k!lQ7)N8 z5#>#03KSiBR-C7p0q Date: Sat, 20 Feb 2021 18:51:08 +0100 Subject: [PATCH 02/24] [Vulcan/Hebe] Update login mode requirement. --- .../java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt index 269cf9ed..d70dd54e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt @@ -121,7 +121,7 @@ val vulcanLoginMethods = listOf( LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_API, VulcanLoginApi::class.java) .withIsPossible { _, loginStore -> - loginStore.mode == LOGIN_MODE_VULCAN_API + loginStore.mode != LOGIN_MODE_VULCAN_HEBE } .withRequiredLoginMethod { _, loginStore -> if (loginStore.mode == LOGIN_MODE_VULCAN_WEB) LOGIN_METHOD_VULCAN_WEB_MAIN else LOGIN_METHOD_NOT_NEEDED @@ -129,7 +129,7 @@ val vulcanLoginMethods = listOf( LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_HEBE, VulcanLoginHebe::class.java) .withIsPossible { _, loginStore -> - loginStore.mode == LOGIN_MODE_VULCAN_HEBE + loginStore.mode != LOGIN_MODE_VULCAN_API } .withRequiredLoginMethod { _, loginStore -> if (loginStore.mode == LOGIN_MODE_VULCAN_WEB) LOGIN_METHOD_VULCAN_WEB_MAIN else LOGIN_METHOD_NOT_NEEDED From aef3f66654cfe405e650f4d340e2aaaed3d16725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 20 Feb 2021 20:11:54 +0100 Subject: [PATCH 03/24] [Vulcan/Hebe] Add API list helper. Separate student list code. --- .../data/api/edziennik/vulcan/DataVulcan.kt | 5 + .../api/edziennik/vulcan/data/VulcanHebe.kt | 63 ++++++- .../vulcan/data/hebe/HebeFilterType.kt | 7 + .../vulcan/data/hebe/VulcanHebeMain.kt | 157 ++++++++++++++++++ .../vulcan/firstlogin/VulcanFirstLogin.kt | 116 ++----------- .../edziennik/vulcan/login/VulcanLoginHebe.kt | 7 +- 6 files changed, 245 insertions(+), 110 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/HebeFilterType.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt index d494ec3d..1b70faff 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt @@ -243,6 +243,11 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app get() { mHebePublicHash = mHebePublicHash ?: loginStore.getLoginData("hebePublicHash", null); return mHebePublicHash } set(value) { loginStore.putLoginData("hebePublicHash", value); mHebePublicHash = value } + private var mHebeContext: String? = null + var hebeContext: String? + get() { mHebeContext = mHebeContext ?: profile?.getStudentData("hebeContext", null); return mHebeContext } + set(value) { profile?.putStudentData("hebeContext", value) ?: return; mHebeContext = value } + val apiUrl: String? get() { val url = when (apiToken[symbol]?.substring(0, 3)) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt index cd8a9b77..42e845f6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt @@ -2,6 +2,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data import android.os.Build import com.google.gson.JsonArray +import com.google.gson.JsonElement import com.google.gson.JsonObject import im.wangchao.mhttp.Request import im.wangchao.mhttp.Response @@ -11,10 +12,14 @@ import io.github.wulkanowy.signer.hebe.getSignatureHeaders import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.HebeFilterType import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.utils.Utils.d +import pl.szczodrzynski.edziennik.utils.models.Date import java.net.HttpURLConnection import java.net.URLEncoder +import java.time.Instant +import java.time.LocalDateTime import java.time.ZoneId import java.time.ZonedDateTime import java.time.format.DateTimeFormatter @@ -35,7 +40,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { tag: String, endpoint: String, method: Int = GET, - payload: JsonObject? = null, + payload: JsonElement? = null, baseUrl: Boolean = false, crossinline onSuccess: (json: T, response: Response?) -> Unit ) { @@ -132,6 +137,8 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { .addHeader("vDeviceModel", Build.MODEL) .addHeader("vAPI", "1") .apply { + if (data.hebeContext != null) + addHeader("vContext", data.hebeContext) headers.forEach { addHeader(it.key, it.value) } @@ -171,7 +178,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { inline fun apiPost( tag: String, endpoint: String, - payload: JsonObject, + payload: JsonElement, baseUrl: Boolean = false, crossinline onSuccess: (json: T, response: Response?) -> Unit ) { @@ -184,4 +191,56 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { onSuccess = onSuccess ) } + + fun apiGetList( + tag: String, + endpoint: String, + filterType: HebeFilterType? = null, + dateFrom: Date? = null, + dateTo: Date? = null, + lastSync: Long? = null, + folder: Int? = null, + params: Map = mapOf(), + includeFilterType: Boolean = true, + onSuccess: (data: List, response: Response?) -> Unit + ) { + val url = if (includeFilterType && filterType != null) + "$endpoint/${filterType.endpoint}" + else endpoint + + val query = params.toMutableMap() + + when (filterType) { + HebeFilterType.BY_PUPIL -> { + // query["unitId"] = data.studentUnitId + query["pupilId"] = data.studentId.toString() + query["periodId"] = data.studentSemesterId.toString() + } + HebeFilterType.BY_PERSON -> { + query["loginId"] = data.studentLoginId.toString() + } + HebeFilterType.BY_PERIOD -> { + query["periodId"] = data.studentSemesterId.toString() + query["pupilId"] = data.studentId.toString() + } + } + + if (dateFrom != null) + query["dateFrom"] = dateFrom.stringY_m_d + if (dateTo != null) + query["dateTo"] = dateTo.stringY_m_d + + if (folder != null) + query["folder"] = folder.toString() + + query["lastId"] = "-2147483648" // don't ask, it's just Vulcan + query["pageSize"] = "500" + query["lastSyncDate"] = LocalDateTime + .ofInstant(Instant.ofEpochMilli(lastSync ?: 0), ZoneId.systemDefault()) + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + + apiGet(tag, url, query) { json: JsonArray, response -> + onSuccess(json.map { it.asJsonObject }, response) + } + } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/HebeFilterType.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/HebeFilterType.kt new file mode 100644 index 00000000..6734ab71 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/HebeFilterType.kt @@ -0,0 +1,7 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe + +enum class HebeFilterType(val endpoint: String) { + BY_PUPIL("byPupil"), + BY_PERSON("byPerson"), + BY_PERIOD("byPeriod") +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt new file mode 100644 index 00000000..4b37bf5e --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt @@ -0,0 +1,157 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe + +import com.google.gson.JsonArray +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_VULCAN +import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MAIN +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_PUSH_CONFIG +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe +import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.utils.models.Date + +class VulcanHebeMain( + override val data: DataVulcan, + override val lastSync: Long? = null +) : VulcanHebe(data, lastSync) { + companion object { + const val TAG = "VulcanHebeMain" + } + + fun getStudents( + profile: Profile?, + profileList: MutableList?, + loginStoreId: Int? = null, + firstProfileId: Int? = null, + onEmpty: (() -> Unit)? = null, + onSuccess: () -> Unit + ) { + if (profile == null && (profileList == null || loginStoreId == null || firstProfileId == null)) + throw IllegalArgumentException() + + apiGet( + TAG, + VULCAN_HEBE_ENDPOINT_MAIN, + query = mapOf("lastSyncDate" to "null"), + baseUrl = profile == null + ) { students: JsonArray, _ -> + if (students.isEmpty()) { + if (onEmpty != null) + onEmpty() + else + onSuccess() + return@apiGet + } + + // safe to assume this will be non-null when creating a profile + var profileId = firstProfileId ?: loginStoreId ?: 1 + + students.forEach { studentEl -> + val student = studentEl.asJsonObject + + val pupil = student.getJsonObject("Pupil") + val studentId = pupil.getInt("Id") ?: return@forEach + + // check the student ID in case of not first login + if (profile != null && data.studentId != studentId) + return@forEach + + val unit = student.getJsonObject("Unit") + //val constituentUnit = student.getJsonObject("ConstituentUnit") + val login = student.getJsonObject("Login") + val periods = student.getJsonArray("Periods")?.map { + it.asJsonObject + } ?: listOf() + + val period = periods.firstOrNull { + it.getBoolean("Current", false) + } ?: return@forEach + + val periodLevel = period.getInt("Level") ?: return@forEach + val semester1 = periods.firstOrNull { + it.getInt("Level") == periodLevel && it.getInt("Number") == 1 + } + val semester2 = periods.firstOrNull { + it.getInt("Level") == periodLevel && it.getInt("Number") == 2 + } + + val schoolSymbol = unit.getString("Symbol") ?: return@forEach + val schoolShort = unit.getString("Short") ?: return@forEach + val schoolCode = "${data.symbol}_$schoolSymbol" + + val studentLoginId = login.getInt("Id") ?: return@forEach + //val studentClassId = student.getInt("IdOddzial") ?: return@forEach + val studentClassName = student.getString("ClassDisplay") ?: return@forEach + val studentFirstName = pupil.getString("FirstName") ?: "" + val studentLastName = pupil.getString("Surname") ?: "" + val studentNameLong = "$studentFirstName $studentLastName".fixName() + val studentNameShort = "$studentFirstName ${studentLastName[0]}.".fixName() + val userLogin = login.getString("Value") ?: "" + + val studentSemesterId = period.getInt("Id") ?: return@forEach + val studentSemesterNumber = period.getInt("Number") ?: return@forEach + + val hebeContext = student.getString("Context") + + val isParent = login.getString("LoginRole").equals("opiekun", ignoreCase = true) + val accountName = if (isParent) + login.getString("DisplayName")?.fixName() + else null + + val dateSemester1Start = semester1 + ?.getJsonObject("Start") + ?.getString("Date") + ?.let { Date.fromY_m_d(it) } + val dateSemester2Start = semester2 + ?.getJsonObject("Start") + ?.getString("Date") + ?.let { Date.fromY_m_d(it) } + val dateYearEnd = semester2 + ?.getJsonObject("End") + ?.getString("Date") + ?.let { Date.fromY_m_d(it) } + + val newProfile = profile ?: Profile( + profileId++, + loginStoreId!!, + LOGIN_TYPE_VULCAN, + studentNameLong, + userLogin, + studentNameLong, + studentNameShort, + accountName + ) + + newProfile.apply { + this.studentClassName = studentClassName + studentData["symbol"] = data.symbol + + studentData["studentId"] = studentId + studentData["studentLoginId"] = studentLoginId + studentData["studentSemesterId"] = studentSemesterId + studentData["studentSemesterNumber"] = studentSemesterNumber + studentData["semester1Id"] = semester1?.getInt("Id") ?: 0 + studentData["semester2Id"] = semester2?.getInt("Id") ?: 0 + studentData["schoolSymbol"] = schoolSymbol + studentData["schoolShort"] = schoolShort + studentData["schoolName"] = schoolCode + studentData["hebeContext"] = hebeContext + } + dateSemester1Start?.let { + newProfile.dateSemester1Start = it + newProfile.studentSchoolYearStart = it.year + } + dateSemester2Start?.let { newProfile.dateSemester2Start = it } + dateYearEnd?.let { newProfile.dateYearEnd = it } + + if (profile != null) + data.setSyncNext(ENDPOINT_VULCAN_API_PUSH_CONFIG, SYNC_ALWAYS) + + profileList?.add(newProfile) + } + + onSuccess() + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt index b670b12a..02d8b9bd 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt @@ -4,7 +4,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.firstlogin -import com.google.gson.JsonArray import org.greenrobot.eventbus.EventBus import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.* @@ -12,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanWebMain +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeMain import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.CufsCertificate import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginApi import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginHebe @@ -210,110 +210,18 @@ class VulcanFirstLogin(val data: DataVulcan, val onSuccess: () -> Unit) { private fun registerDeviceHebe(onSuccess: () -> Unit) { VulcanLoginHebe(data) { - hebe.apiGet( - TAG, - VULCAN_HEBE_ENDPOINT_MAIN, - query = mapOf("lastSyncDate" to "null"), - baseUrl = true - ) { students: JsonArray, _ -> - if (students.isEmpty()) { - EventBus.getDefault().postSticky(FirstLoginFinishedEvent(listOf(), data.loginStore)) + VulcanHebeMain(data).getStudents( + profile = null, + profileList, + loginStoreId, + firstProfileId, + onEmpty = { + EventBus.getDefault() + .postSticky(FirstLoginFinishedEvent(listOf(), data.loginStore)) onSuccess() - return@apiGet - } - - students.forEach { studentEl -> - val student = studentEl.asJsonObject - - val unit = student.getJsonObject("Unit") - //val constituentUnit = student.getJsonObject("ConstituentUnit") - val pupil = student.getJsonObject("Pupil") - val login = student.getJsonObject("Login") - val periods = student.getJsonArray("Periods")?.map { - it.asJsonObject - } ?: listOf() - - val period = periods.firstOrNull { - it.getBoolean("Current", false) - } ?: return@forEach - - val periodLevel = period.getInt("Level") ?: return@forEach - val semester1 = periods.firstOrNull { - it.getInt("Level") == periodLevel && it.getInt("Number") == 1 - } - val semester2 = periods.firstOrNull { - it.getInt("Level") == periodLevel && it.getInt("Number") == 2 - } - - val schoolSymbol = unit.getString("Symbol") ?: return@forEach - val schoolShort = unit.getString("Short") ?: return@forEach - val schoolCode = "${data.symbol}_$schoolSymbol" - val studentId = pupil.getInt("Id") ?: return@forEach - val studentLoginId = login.getInt("Id") ?: return@forEach - //val studentClassId = student.getInt("IdOddzial") ?: return@forEach - val studentClassName = student.getString("ClassDisplay") ?: return@forEach - val studentFirstName = pupil.getString("FirstName") ?: "" - val studentLastName = pupil.getString("Surname") ?: "" - val studentNameLong = "$studentFirstName $studentLastName".fixName() - val studentNameShort = "$studentFirstName ${studentLastName[0]}.".fixName() - val userLogin = login.getString("Value") ?: "" - - val studentSemesterId = period.getInt("Id") ?: return@forEach - val studentSemesterNumber = period.getInt("Number") ?: return@forEach - - val isParent = login.getString("LoginRole").equals("opiekun", ignoreCase = true) - val accountName = if (isParent) - login.getString("DisplayName")?.fixName() - else null - - val dateSemester1Start = semester1 - ?.getJsonObject("Start") - ?.getString("Date") - ?.let { Date.fromY_m_d(it) } - val dateSemester2Start = semester2 - ?.getJsonObject("Start") - ?.getString("Date") - ?.let { Date.fromY_m_d(it) } - val dateYearEnd = semester2 - ?.getJsonObject("End") - ?.getString("Date") - ?.let { Date.fromY_m_d(it) } - - val profile = Profile( - firstProfileId++, - loginStoreId, - LOGIN_TYPE_VULCAN, - studentNameLong, - userLogin, - studentNameLong, - studentNameShort, - accountName - ).apply { - this.studentClassName = studentClassName - studentData["symbol"] = data.symbol - - studentData["studentId"] = studentId - studentData["studentLoginId"] = studentLoginId - studentData["studentSemesterId"] = studentSemesterId - studentData["studentSemesterNumber"] = studentSemesterNumber - studentData["semester1Id"] = semester1?.getInt("Id") ?: 0 - studentData["semester2Id"] = semester2?.getInt("Id") ?: 0 - studentData["schoolSymbol"] = schoolSymbol - studentData["schoolShort"] = schoolShort - studentData["schoolName"] = schoolCode - } - dateSemester1Start?.let { - profile.dateSemester1Start = it - profile.studentSchoolYearStart = it.year - } - dateSemester2Start?.let { profile.dateSemester2Start = it } - dateYearEnd?.let { profile.dateYearEnd = it } - - profileList.add(profile) - } - - onSuccess() - } + }, + onSuccess = onSuccess + ) } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt index b2c27454..750fd4ea 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt @@ -9,7 +9,6 @@ import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_REGISTER_NEW import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.api.models.ApiError -import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi import pl.szczodrzynski.edziennik.getString import pl.szczodrzynski.edziennik.isNotNullNorEmpty @@ -64,7 +63,7 @@ class VulcanLoginHebe(val data: DataVulcan, val onSuccess: () -> Unit) { } private fun loginWithToken() { - val szkolnyApi = SzkolnyApi(data.app) + //val szkolnyApi = SzkolnyApi(data.app) val hebe = VulcanHebe(data, null) if (data.hebePublicKey == null || data.hebePrivateKey == null || data.hebePublicHash == null) { @@ -74,11 +73,11 @@ class VulcanLoginHebe(val data: DataVulcan, val onSuccess: () -> Unit) { data.hebePublicHash = publicHash } - szkolnyApi.runCatching({ + /*szkolnyApi.runCatching({ data.app.config.sync.tokenVulcanHebe = getFirebaseToken("vulcan") }, onError = { // screw errors - }) + })*/ hebe.apiPost( TAG, From ae20c30c881c3956a96c01d1deb0432a2d1de7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 20 Feb 2021 21:31:52 +0100 Subject: [PATCH 04/24] [Vulcan/Hebe] Fix Firebase token for registration. --- .../data/api/edziennik/vulcan/data/VulcanHebe.kt | 7 ++++++- .../api/edziennik/vulcan/login/VulcanLoginHebe.kt | 12 +++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt index 42e845f6..dd8913f1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt @@ -42,6 +42,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { method: Int = GET, payload: JsonElement? = null, baseUrl: Boolean = false, + firebaseToken: String? = null, crossinline onSuccess: (json: T, response: Response?) -> Unit ) { val url = "${if (baseUrl) data.apiUrl else data.fullApiUrl}$endpoint" @@ -66,7 +67,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { "AppVersion" to VULCAN_HEBE_APP_VERSION, "CertificateId" to publicHash, "Envelope" to payload, - "FirebaseToken" to data.app.config.sync.tokenVulcanHebe, + "FirebaseToken" to (firebaseToken ?: data.app.config.sync.tokenVulcanHebe), "API" to 1, "RequestId" to UUID.randomUUID().toString(), "Timestamp" to timestampMillis, @@ -164,6 +165,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { endpoint: String, query: Map = mapOf(), baseUrl: Boolean = false, + firebaseToken: String? = null, crossinline onSuccess: (json: T, response: Response?) -> Unit ) { val queryPath = query.map { it.key + "=" + URLEncoder.encode(it.value, "UTF-8") }.join("&") @@ -171,6 +173,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { tag, if (query.isNotEmpty()) "$endpoint?$queryPath" else endpoint, baseUrl = baseUrl, + firebaseToken = firebaseToken, onSuccess = onSuccess ) } @@ -180,6 +183,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { endpoint: String, payload: JsonElement, baseUrl: Boolean = false, + firebaseToken: String? = null, crossinline onSuccess: (json: T, response: Response?) -> Unit ) { apiRequest( @@ -188,6 +192,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { method = POST, payload, baseUrl = baseUrl, + firebaseToken = firebaseToken, onSuccess = onSuccess ) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt index 750fd4ea..1308f449 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLoginHebe.kt @@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_REGISTER_NEW import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi import pl.szczodrzynski.edziennik.getString import pl.szczodrzynski.edziennik.isNotNullNorEmpty @@ -63,7 +64,7 @@ class VulcanLoginHebe(val data: DataVulcan, val onSuccess: () -> Unit) { } private fun loginWithToken() { - //val szkolnyApi = SzkolnyApi(data.app) + val szkolnyApi = SzkolnyApi(data.app) val hebe = VulcanHebe(data, null) if (data.hebePublicKey == null || data.hebePrivateKey == null || data.hebePublicHash == null) { @@ -73,11 +74,11 @@ class VulcanLoginHebe(val data: DataVulcan, val onSuccess: () -> Unit) { data.hebePublicHash = publicHash } - /*szkolnyApi.runCatching({ - data.app.config.sync.tokenVulcanHebe = getFirebaseToken("vulcan") + val firebaseToken = szkolnyApi.runCatching({ + getFirebaseToken("vulcan") }, onError = { // screw errors - })*/ + }) ?: data.app.config.sync.tokenVulcan hebe.apiPost( TAG, @@ -92,7 +93,8 @@ class VulcanLoginHebe(val data: DataVulcan, val onSuccess: () -> Unit) { "SelfIdentifier" to data.buildDeviceId(), "CertificateThumbprint" to data.hebePublicHash ), - baseUrl = true + baseUrl = true, + firebaseToken = firebaseToken ) { _: JsonObject, _ -> data.apiToken = data.apiToken.toMutableMap().also { it[data.symbol] = it[data.symbol]?.substring(0, 3) From c7d2ac4e3ee9cdd812418610b9278f4babd6c620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 20 Feb 2021 23:07:23 +0100 Subject: [PATCH 05/24] [Vulcan/Hebe] Add getting grades. --- .../edziennik/data/api/Constants.kt | 1 + .../api/edziennik/vulcan/VulcanFeatures.kt | 5 + .../api/edziennik/vulcan/data/VulcanData.kt | 5 + .../api/edziennik/vulcan/data/VulcanHebe.kt | 48 ++++++- .../vulcan/data/hebe/VulcanHebeGrades.kt | 119 ++++++++++++++++++ .../vulcan/data/hebe/VulcanHebeMain.kt | 5 +- 6 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index 016d0eb4..f8a0e48b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -127,6 +127,7 @@ const val VULCAN_WEB_ENDPOINT_LUCKY_NUMBER = "Start.mvc/GetKidsLuckyNumbers" const val VULCAN_WEB_ENDPOINT_REGISTER_DEVICE = "RejestracjaUrzadzeniaToken.mvc/Get" const val VULCAN_HEBE_ENDPOINT_REGISTER_NEW = "api/mobile/register/new" const val VULCAN_HEBE_ENDPOINT_MAIN = "api/mobile/register/hebe" +const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade" const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt index ab032e0c..a5121572 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt @@ -20,6 +20,8 @@ const val ENDPOINT_VULCAN_API_ATTENDANCE = 1080 const val ENDPOINT_VULCAN_API_MESSAGES_INBOX = 1090 const val ENDPOINT_VULCAN_API_MESSAGES_SENT = 1100 const val ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS = 2010 +const val ENDPOINT_VULCAN_HEBE_MAIN = 3000 +const val ENDPOINT_VULCAN_HEBE_GRADES = 3040 val VulcanFeatures = listOf( // timetable @@ -35,6 +37,9 @@ val VulcanFeatures = listOf( ENDPOINT_VULCAN_API_GRADES to LOGIN_METHOD_VULCAN_API, ENDPOINT_VULCAN_API_GRADES_SUMMARY to LOGIN_METHOD_VULCAN_API ), listOf(LOGIN_METHOD_VULCAN_API)), + Feature(LOGIN_TYPE_VULCAN, FEATURE_GRADES, listOf( + ENDPOINT_VULCAN_HEBE_GRADES to LOGIN_METHOD_VULCAN_HEBE + ), listOf(LOGIN_METHOD_VULCAN_HEBE)), // homework Feature(LOGIN_TYPE_VULCAN, FEATURE_HOMEWORK, listOf( ENDPOINT_VULCAN_API_HOMEWORK to LOGIN_METHOD_VULCAN_API diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt index 491e8ea6..793485f4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt @@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.* +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeGrades import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.web.VulcanWebLuckyNumber import pl.szczodrzynski.edziennik.utils.Utils @@ -91,6 +92,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { data.startProgress(R.string.edziennik_progress_endpoint_lucky_number) VulcanWebLuckyNumber(data, lastSync, onSuccess) } + ENDPOINT_VULCAN_HEBE_GRADES -> { + data.startProgress(R.string.edziennik_progress_endpoint_grades) + VulcanHebeGrades(data, lastSync, onSuccess) + } else -> onSuccess(endpointId) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt index dd8913f1..cae27d43 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt @@ -1,6 +1,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data import android.os.Build +import androidx.core.util.set import com.google.gson.JsonArray import com.google.gson.JsonElement import com.google.gson.JsonObject @@ -14,6 +15,8 @@ import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.HebeFilterType import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.db.entity.Subject +import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.models.Date import java.net.HttpURLConnection @@ -36,6 +39,47 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { val profile get() = data.profile + fun getDate(json: JsonObject?, key: String): Long { + val date = json.getJsonObject(key) + return date.getLong("Timestamp") ?: return System.currentTimeMillis() + } + + fun getTeacherId(json: JsonObject?, key: String): Long { + val teacher = json.getJsonObject(key) + val teacherId = teacher.getLong("Id") ?: return -1 + if (data.teacherList[teacherId] == null) { + data.teacherList[teacherId] = Teacher( + data.profileId, + teacherId, + teacher.getString("Name") ?: "", + teacher.getString("Surname") ?: "" + ) + } + return teacherId + } + + fun getSubjectId(json: JsonObject?, key: String): Long { + val subject = json.getJsonObject(key) + val subjectId = subject.getLong("Id") ?: return -1 + if (data.subjectList[subjectId] == null) { + data.subjectList[subjectId] = Subject( + data.profileId, + subjectId, + subject.getString("Name") ?: "", + subject.getString("Kod") ?: "" + ) + } + return subjectId + } + + fun getSemester(json: JsonObject?): Int { + val periodId = json.getInt("PeriodId") ?: return 1 + return if (periodId == data.semester1Id) + 1 + else + 2 + } + inline fun apiRequest( tag: String, endpoint: String, @@ -168,7 +212,9 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { firebaseToken: String? = null, crossinline onSuccess: (json: T, response: Response?) -> Unit ) { - val queryPath = query.map { it.key + "=" + URLEncoder.encode(it.value, "UTF-8") }.join("&") + val queryPath = query.map { + it.key + "=" + URLEncoder.encode(it.value, "UTF-8").replace("+", "%20") + }.join("&") apiRequest( tag, if (query.isNotEmpty()) "$endpoint?$queryPath" else endpoint, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt new file mode 100644 index 00000000..6d78a673 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt @@ -0,0 +1,119 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe + +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_GRADES +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_GRADES +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe +import pl.szczodrzynski.edziennik.data.db.entity.Grade +import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import java.text.DecimalFormat +import kotlin.math.roundToInt + +class VulcanHebeGrades( + override val data: DataVulcan, + override val lastSync: Long?, + val onSuccess: (endpointId: Int) -> Unit +) : VulcanHebe(data, lastSync) { + companion object { + const val TAG = "VulcanApiGrades" + } + + init { + apiGetList( + TAG, + VULCAN_HEBE_ENDPOINT_GRADES, + HebeFilterType.BY_PUPIL, + lastSync = lastSync + ) { list, _ -> + list.forEach { grade -> + val id = grade.getLong("Id") ?: return@forEach + + val column = grade.getJsonObject("Column") + val category = column.getJsonObject("Category") + val categoryText = category.getString("Name") + + val teacherId = getTeacherId(grade, "Creator") + val subjectId = getSubjectId(column, "Subject") + + val description = column.getString("Name") + val comment = grade.getString("Comment") + var value = grade.getFloat("Value") + var weight = column.getFloat("Weight") ?: 0.0f + val numerator = grade.getFloat("Numerator ") + val denominator = grade.getFloat("Denominator") + val addedDate = getDate(grade, "DateModify") + + var finalDescription = "" + + var name = when (numerator != null && denominator != null) { + true -> { + value = numerator / denominator + finalDescription += DecimalFormat("#.##").format(numerator) + + "/" + DecimalFormat("#.##").format(denominator) + weight = 0.0f + (value * 100).roundToInt().toString() + "%" + } + else -> { + if (value == null) weight = 0.0f + + grade.getString("Content") ?: "" + } + } + + comment?.also { + if (name == "") name = it + else finalDescription = (if (finalDescription == "") "" else " ") + it + } + + description?.also { + finalDescription = (if (finalDescription == "") "" else " - ") + it + } + + val columnColor = column.getInt("Color") ?: 0 + val color = if (columnColor == 0) + when (name) { + "1-", "1", "1+" -> 0xffd65757 + "2-", "2", "2+" -> 0xff9071b3 + "3-", "3", "3+" -> 0xffd2ab24 + "4-", "4", "4+" -> 0xff50b6d6 + "5-", "5", "5+" -> 0xff2cbd92 + "6-", "6", "6+" -> 0xff91b43c + else -> 0xff3D5F9C + }.toInt() + else + columnColor + + val gradeObject = Grade( + profileId = profileId, + id = id, + name = name, + type = Grade.TYPE_NORMAL, + value = value ?: 0.0f, + weight = weight, + color = color, + category = categoryText, + description = finalDescription, + comment = null, + semester = getSemester(column), + teacherId = teacherId, + subjectId = subjectId, + addedDate = addedDate + ) + + data.gradeList.add(gradeObject) + data.metadataList.add( + Metadata( + profileId, + Metadata.TYPE_GRADE, + id, + profile?.empty ?: true, + profile?.empty ?: true + ) + ) + } + + onSuccess(ENDPOINT_VULCAN_HEBE_GRADES) + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt index 4b37bf5e..438c50ae 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt @@ -5,10 +5,9 @@ import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_VULCAN import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MAIN import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan -import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_PUSH_CONFIG +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_MAIN import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.db.entity.Profile -import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.utils.models.Date class VulcanHebeMain( @@ -146,7 +145,7 @@ class VulcanHebeMain( dateYearEnd?.let { newProfile.dateYearEnd = it } if (profile != null) - data.setSyncNext(ENDPOINT_VULCAN_API_PUSH_CONFIG, SYNC_ALWAYS) + data.setSyncNext(ENDPOINT_VULCAN_HEBE_MAIN, 1 * DAY) profileList?.add(newProfile) } From 2aaf713d5818299f26f56187541dcefce51b475e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 20 Feb 2021 23:45:27 +0100 Subject: [PATCH 06/24] [Vulcan/Hebe] Add next sync and data removing in grades. --- .../api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt index 6d78a673..99e38f3f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt @@ -5,8 +5,10 @@ import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_GRADES import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_GRADES import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe +import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import java.text.DecimalFormat import kotlin.math.roundToInt @@ -114,6 +116,11 @@ class VulcanHebeGrades( } onSuccess(ENDPOINT_VULCAN_HEBE_GRADES) + data.toRemove.add( + DataRemoveModel.Grades.semesterWithType(data.studentSemesterNumber, + Grade.TYPE_NORMAL + )) + data.setSyncNext(ENDPOINT_VULCAN_HEBE_GRADES, SYNC_ALWAYS) } } } From 4fc965d970c436706818425c01eba3bfc3370aeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 20 Feb 2021 23:52:40 +0100 Subject: [PATCH 07/24] [Vulcan/Hebe] Add saving unit ID. --- .../edziennik/data/api/edziennik/vulcan/DataVulcan.kt | 10 ++++++++++ .../data/api/edziennik/vulcan/data/VulcanHebe.kt | 2 +- .../api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt | 6 +++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt index 1b70faff..19e28e3a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt @@ -158,6 +158,16 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app get() { mStudentSemesterId = mStudentSemesterId ?: profile?.getStudentData("studentSemesterId", 0); return mStudentSemesterId ?: 0 } set(value) { profile?.putStudentData("studentSemesterId", value) ?: return; mStudentSemesterId = value } + private var mStudentUnitId: Int? = null + var studentUnitId: Int + get() { mStudentUnitId = mStudentUnitId ?: profile?.getStudentData("studentUnitId", 0); return mStudentUnitId ?: 0 } + set(value) { profile?.putStudentData("studentUnitId", value) ?: return; mStudentUnitId = value } + + private var mStudentConstituentId: Int? = null + var studentConstituentId: Int + get() { mStudentConstituentId = mStudentConstituentId ?: profile?.getStudentData("studentConstituentId", 0); return mStudentConstituentId ?: 0 } + set(value) { profile?.putStudentData("studentConstituentId", value) ?: return; mStudentConstituentId = value } + private var mSemester1Id: Int? = null var semester1Id: Int get() { mSemester1Id = mSemester1Id ?: profile?.getStudentData("semester1Id", 0); return mSemester1Id ?: 0 } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt index cae27d43..cf6beff8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt @@ -263,7 +263,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { when (filterType) { HebeFilterType.BY_PUPIL -> { - // query["unitId"] = data.studentUnitId + query["unitId"] = data.studentUnitId.toString() query["pupilId"] = data.studentId.toString() query["periodId"] = data.studentSemesterId.toString() } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt index 438c50ae..020509c3 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt @@ -57,7 +57,7 @@ class VulcanHebeMain( return@forEach val unit = student.getJsonObject("Unit") - //val constituentUnit = student.getJsonObject("ConstituentUnit") + val constituentUnit = student.getJsonObject("ConstituentUnit") val login = student.getJsonObject("Login") val periods = student.getJsonArray("Periods")?.map { it.asJsonObject @@ -79,6 +79,8 @@ class VulcanHebeMain( val schoolShort = unit.getString("Short") ?: return@forEach val schoolCode = "${data.symbol}_$schoolSymbol" + val studentUnitId = unit.getInt("Id") ?: return@forEach + val studentConstituentId = constituentUnit.getInt("Id") ?: return@forEach val studentLoginId = login.getInt("Id") ?: return@forEach //val studentClassId = student.getInt("IdOddzial") ?: return@forEach val studentClassName = student.getString("ClassDisplay") ?: return@forEach @@ -127,6 +129,8 @@ class VulcanHebeMain( studentData["symbol"] = data.symbol studentData["studentId"] = studentId + studentData["studentUnitId"] = studentUnitId + studentData["studentConstituentId"] = studentConstituentId studentData["studentLoginId"] = studentLoginId studentData["studentSemesterId"] = studentSemesterId studentData["studentSemesterNumber"] = studentSemesterNumber From 28725c6400ab188828791769dbf41d4b67b169d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 00:27:42 +0100 Subject: [PATCH 08/24] [Vulcan/Hebe] Add getting exams. --- .../edziennik/data/api/Constants.kt | 1 + .../api/edziennik/vulcan/VulcanFeatures.kt | 4 + .../api/edziennik/vulcan/data/VulcanData.kt | 5 ++ .../api/edziennik/vulcan/data/VulcanHebe.kt | 43 +++++++++- .../vulcan/data/hebe/VulcanHebeExams.kt | 80 +++++++++++++++++++ .../vulcan/data/hebe/VulcanHebeGrades.kt | 6 +- 6 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeExams.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index f8a0e48b..55b0e878 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -127,6 +127,7 @@ const val VULCAN_WEB_ENDPOINT_LUCKY_NUMBER = "Start.mvc/GetKidsLuckyNumbers" const val VULCAN_WEB_ENDPOINT_REGISTER_DEVICE = "RejestracjaUrzadzeniaToken.mvc/Get" const val VULCAN_HEBE_ENDPOINT_REGISTER_NEW = "api/mobile/register/new" const val VULCAN_HEBE_ENDPOINT_MAIN = "api/mobile/register/hebe" +const val VULCAN_HEBE_ENDPOINT_EXAMS = "api/mobile/exam" const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade" const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt index a5121572..547037ad 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt @@ -21,6 +21,7 @@ const val ENDPOINT_VULCAN_API_MESSAGES_INBOX = 1090 const val ENDPOINT_VULCAN_API_MESSAGES_SENT = 1100 const val ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS = 2010 const val ENDPOINT_VULCAN_HEBE_MAIN = 3000 +const val ENDPOINT_VULCAN_HEBE_EXAMS = 3030 const val ENDPOINT_VULCAN_HEBE_GRADES = 3040 val VulcanFeatures = listOf( @@ -32,6 +33,9 @@ val VulcanFeatures = listOf( Feature(LOGIN_TYPE_VULCAN, FEATURE_AGENDA, listOf( ENDPOINT_VULCAN_API_EVENTS to LOGIN_METHOD_VULCAN_API ), listOf(LOGIN_METHOD_VULCAN_API)), + Feature(LOGIN_TYPE_VULCAN, FEATURE_AGENDA, listOf( + ENDPOINT_VULCAN_HEBE_EXAMS to LOGIN_METHOD_VULCAN_HEBE + ), listOf(LOGIN_METHOD_VULCAN_HEBE)), // grades Feature(LOGIN_TYPE_VULCAN, FEATURE_GRADES, listOf( ENDPOINT_VULCAN_API_GRADES to LOGIN_METHOD_VULCAN_API, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt index 793485f4..d0b93a27 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt @@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.* +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeExams import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeGrades import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.web.VulcanWebLuckyNumber import pl.szczodrzynski.edziennik.utils.Utils @@ -92,6 +93,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { data.startProgress(R.string.edziennik_progress_endpoint_lucky_number) VulcanWebLuckyNumber(data, lastSync, onSuccess) } + ENDPOINT_VULCAN_HEBE_EXAMS -> { + data.startProgress(R.string.edziennik_progress_endpoint_exams) + VulcanHebeExams(data, lastSync, onSuccess) + } ENDPOINT_VULCAN_HEBE_GRADES -> { data.startProgress(R.string.edziennik_progress_endpoint_grades) VulcanHebeGrades(data, lastSync, onSuccess) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt index cf6beff8..526099b4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt @@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.HebeFilter import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.db.entity.Subject import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.entity.Team import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.models.Date import java.net.HttpURLConnection @@ -39,11 +40,16 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { val profile get() = data.profile - fun getDate(json: JsonObject?, key: String): Long { + fun getDateTime(json: JsonObject?, key: String): Long { val date = json.getJsonObject(key) return date.getLong("Timestamp") ?: return System.currentTimeMillis() } + fun getDate(json: JsonObject?, key: String): Date? { + val date = json.getJsonObject(key) + return date.getString("Date")?.let { Date.fromY_m_d(it) } + } + fun getTeacherId(json: JsonObject?, key: String): Long { val teacher = json.getJsonObject(key) val teacherId = teacher.getLong("Id") ?: return -1 @@ -72,6 +78,41 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { return subjectId } + fun getTeamId(json: JsonObject?, key: String): Long? { + val team = json.getJsonObject(key) + val teamId = team.getLong("Id") ?: return null + if (data.teamList[teamId] == null) { + data.teamList[teamId] = Team( + data.profileId, + teamId, + team.getString("Name") ?: "", + Team.TYPE_VIRTUAL, + team.getString("Shortcut") ?: "", + -1 + ) + } + return teamId + } + + fun getClassId(json: JsonObject?, key: String): Long? { + val team = json.getJsonObject(key) + val teamId = team.getLong("Id") ?: return null + if (data.teamList[teamId] == null) { + val name = data.profile?.studentClassName + ?: team.getString("Name") + ?: "" + data.teamList[teamId] = Team( + data.profileId, + teamId, + name, + Team.TYPE_CLASS, + name, + -1 + ) + } + return teamId + } + fun getSemester(json: JsonObject?): Int { val periodId = json.getInt("PeriodId") ?: return 1 return if (periodId == data.semester1Id) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeExams.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeExams.kt new file mode 100644 index 00000000..d5567780 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeExams.kt @@ -0,0 +1,80 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe + +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_EXAMS +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_EXAMS +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe +import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel +import pl.szczodrzynski.edziennik.data.db.entity.Event +import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS + +class VulcanHebeExams( + override val data: DataVulcan, + override val lastSync: Long?, + val onSuccess: (endpointId: Int) -> Unit +) : VulcanHebe(data, lastSync) { + companion object { + const val TAG = "VulcanHebeExams" + } + + init { + apiGetList( + TAG, + VULCAN_HEBE_ENDPOINT_EXAMS, + HebeFilterType.BY_PUPIL, + lastSync = lastSync + ) { list, _ -> + list.forEach { exam -> + val id = exam.getLong("Id") ?: return@forEach + val eventDate = getDate(exam, "Deadline") ?: return@forEach + val subjectId = getSubjectId(exam, "Subject") + val teacherId = getTeacherId(exam, "Creator") + val teamId = getTeamId(exam, "Distribution") + ?: getClassId(exam, "Class") + ?: data.teamClass?.id + ?: -1 + val topic = exam.getString("Content")?.trim() ?: "" + + val lessonList = data.db.timetableDao().getAllForDateNow(profileId, eventDate) + val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime + + val type = when (exam.getString("Type")) { + "Praca klasowa", + "Sprawdzian" -> Event.TYPE_EXAM + "Kartkówka" -> Event.TYPE_SHORT_QUIZ + else -> Event.TYPE_DEFAULT + } + + val eventObject = Event( + profileId = profileId, + id = id, + date = eventDate, + time = startTime, + topic = topic, + color = null, + type = type, + teacherId = teacherId, + subjectId = subjectId, + teamId = teamId + ) + + data.eventList.add(eventObject) + data.metadataList.add( + Metadata( + profileId, + Metadata.TYPE_EVENT, + id, + profile?.empty ?: true, + profile?.empty ?: true + ) + ) + } + + data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK)) + data.setSyncNext(ENDPOINT_VULCAN_HEBE_EXAMS, SYNC_ALWAYS) + onSuccess(ENDPOINT_VULCAN_HEBE_EXAMS) + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt index 99e38f3f..815f5ab1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt @@ -18,7 +18,7 @@ class VulcanHebeGrades( val onSuccess: (endpointId: Int) -> Unit ) : VulcanHebe(data, lastSync) { companion object { - const val TAG = "VulcanApiGrades" + const val TAG = "VulcanHebeGrades" } init { @@ -44,7 +44,7 @@ class VulcanHebeGrades( var weight = column.getFloat("Weight") ?: 0.0f val numerator = grade.getFloat("Numerator ") val denominator = grade.getFloat("Denominator") - val addedDate = getDate(grade, "DateModify") + val addedDate = getDateTime(grade, "DateModify") var finalDescription = "" @@ -115,12 +115,12 @@ class VulcanHebeGrades( ) } - onSuccess(ENDPOINT_VULCAN_HEBE_GRADES) data.toRemove.add( DataRemoveModel.Grades.semesterWithType(data.studentSemesterNumber, Grade.TYPE_NORMAL )) data.setSyncNext(ENDPOINT_VULCAN_HEBE_GRADES, SYNC_ALWAYS) + onSuccess(ENDPOINT_VULCAN_HEBE_GRADES) } } } From d6a67a0da6de69826c4b6f863a7a7fd1385a62ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 12:18:53 +0100 Subject: [PATCH 09/24] [Vulcan/Hebe] Add getting homework list. --- .../edziennik/data/api/Constants.kt | 1 + .../data/api/edziennik/vulcan/DataVulcan.kt | 4 +- .../api/edziennik/vulcan/VulcanFeatures.kt | 4 ++ .../api/edziennik/vulcan/data/VulcanData.kt | 5 ++ .../api/edziennik/vulcan/data/VulcanHebe.kt | 10 ++- .../vulcan/data/hebe/VulcanHebeHomework.kt | 71 +++++++++++++++++++ 6 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeHomework.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index 55b0e878..d3fd18ed 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -129,6 +129,7 @@ const val VULCAN_HEBE_ENDPOINT_REGISTER_NEW = "api/mobile/register/new" const val VULCAN_HEBE_ENDPOINT_MAIN = "api/mobile/register/hebe" const val VULCAN_HEBE_ENDPOINT_EXAMS = "api/mobile/exam" const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade" +const val VULCAN_HEBE_ENDPOINT_HOMEWORK = "api/mobile/homework" const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt index 19e28e3a..90ba3dd6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt @@ -8,6 +8,7 @@ import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_API import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_HEBE import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_WEB_MAIN +import pl.szczodrzynski.edziennik.data.api.LOGIN_MODE_VULCAN_API import pl.szczodrzynski.edziennik.data.api.models.Data import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile @@ -44,7 +45,8 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app init { // during the first sync `profile.studentClassName` is already set - if (teamList.values().none { it.type == Team.TYPE_CLASS }) { + if (loginStore.mode == LOGIN_MODE_VULCAN_API + && teamList.values().none { it.type == Team.TYPE_CLASS }) { profile?.studentClassName?.also { name -> val id = Utils.crc16(name.toByteArray()).toLong() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt index 547037ad..466f0dcf 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt @@ -23,6 +23,7 @@ const val ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS = 2010 const val ENDPOINT_VULCAN_HEBE_MAIN = 3000 const val ENDPOINT_VULCAN_HEBE_EXAMS = 3030 const val ENDPOINT_VULCAN_HEBE_GRADES = 3040 +const val ENDPOINT_VULCAN_HEBE_HOMEWORK = 3060 val VulcanFeatures = listOf( // timetable @@ -48,6 +49,9 @@ val VulcanFeatures = listOf( Feature(LOGIN_TYPE_VULCAN, FEATURE_HOMEWORK, listOf( ENDPOINT_VULCAN_API_HOMEWORK to LOGIN_METHOD_VULCAN_API ), listOf(LOGIN_METHOD_VULCAN_API)), + Feature(LOGIN_TYPE_VULCAN, FEATURE_HOMEWORK, listOf( + ENDPOINT_VULCAN_HEBE_HOMEWORK to LOGIN_METHOD_VULCAN_HEBE + ), listOf(LOGIN_METHOD_VULCAN_HEBE)), // behaviour Feature(LOGIN_TYPE_VULCAN, FEATURE_BEHAVIOUR, listOf( ENDPOINT_VULCAN_API_NOTICES to LOGIN_METHOD_VULCAN_API diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt index d0b93a27..fb568815 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt @@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeExams import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeGrades +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeHomework import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.web.VulcanWebLuckyNumber import pl.szczodrzynski.edziennik.utils.Utils @@ -101,6 +102,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { data.startProgress(R.string.edziennik_progress_endpoint_grades) VulcanHebeGrades(data, lastSync, onSuccess) } + ENDPOINT_VULCAN_HEBE_HOMEWORK -> { + data.startProgress(R.string.edziennik_progress_endpoint_homework) + VulcanHebeHomework(data, lastSync, onSuccess) + } else -> onSuccess(endpointId) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt index 526099b4..d8df2f8c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt @@ -82,12 +82,16 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { val team = json.getJsonObject(key) val teamId = team.getLong("Id") ?: return null if (data.teamList[teamId] == null) { + var name = team.getString("Shortcut") + ?: team.getString("Name") + ?: "" + name = "${profile?.studentClassName ?: ""} $name" data.teamList[teamId] = Team( data.profileId, teamId, - team.getString("Name") ?: "", + name, Team.TYPE_VIRTUAL, - team.getString("Shortcut") ?: "", + "${data.schoolCode}:$name", -1 ) } @@ -106,7 +110,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { teamId, name, Team.TYPE_CLASS, - name, + "${data.schoolCode}:$name", -1 ) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeHomework.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeHomework.kt new file mode 100644 index 00000000..5e7f3e33 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeHomework.kt @@ -0,0 +1,71 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe + +import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_HOMEWORK +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_HOMEWORK +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe +import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel +import pl.szczodrzynski.edziennik.data.db.entity.Event +import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.getLong +import pl.szczodrzynski.edziennik.getString + +class VulcanHebeHomework( + override val data: DataVulcan, + override val lastSync: Long?, + val onSuccess: (endpointId: Int) -> Unit +) : VulcanHebe(data, lastSync) { + companion object { + const val TAG = "VulcanHebeHomework" + } + + init { + apiGetList( + TAG, + VULCAN_HEBE_ENDPOINT_HOMEWORK, + HebeFilterType.BY_PUPIL, + lastSync = lastSync + ) { list, _ -> + list.forEach { exam -> + val id = exam.getLong("IdHomework") ?: return@forEach + val eventDate = getDate(exam, "Deadline") ?: return@forEach + val subjectId = getSubjectId(exam, "Subject") + val teacherId = getTeacherId(exam, "Creator") + val teamId = data.teamClass?.id ?: -1 + val topic = exam.getString("Content")?.trim() ?: "" + + val lessonList = data.db.timetableDao().getAllForDateNow(profileId, eventDate) + val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime + + val eventObject = Event( + profileId = profileId, + id = id, + date = eventDate, + time = startTime, + topic = topic, + color = null, + type = Event.TYPE_HOMEWORK, + teacherId = teacherId, + subjectId = subjectId, + teamId = teamId + ) + + data.eventList.add(eventObject) + data.metadataList.add( + Metadata( + profileId, + Metadata.TYPE_HOMEWORK, + id, + profile?.empty ?: true, + profile?.empty ?: true + ) + ) + } + + data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK)) + data.setSyncNext(ENDPOINT_VULCAN_HEBE_HOMEWORK, SYNC_ALWAYS) + onSuccess(ENDPOINT_VULCAN_HEBE_HOMEWORK) + } + } +} From 54e49af943f4dde692986e9acf576a41f71ba547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 16:18:33 +0100 Subject: [PATCH 10/24] [Vulcan/Hebe] Add getting timetable and lesson changes. --- .../edziennik/data/api/Constants.kt | 2 + .../api/edziennik/vulcan/VulcanFeatures.kt | 4 + .../api/edziennik/vulcan/data/VulcanData.kt | 5 + .../api/edziennik/vulcan/data/VulcanHebe.kt | 25 +- .../vulcan/data/hebe/VulcanHebeExams.kt | 6 +- .../vulcan/data/hebe/VulcanHebeGrades.kt | 9 +- .../vulcan/data/hebe/VulcanHebeHomework.kt | 6 +- .../vulcan/data/hebe/VulcanHebeTimetable.kt | 247 ++++++++++++++++++ 8 files changed, 285 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index d3fd18ed..e5d8b7b6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -127,6 +127,8 @@ const val VULCAN_WEB_ENDPOINT_LUCKY_NUMBER = "Start.mvc/GetKidsLuckyNumbers" const val VULCAN_WEB_ENDPOINT_REGISTER_DEVICE = "RejestracjaUrzadzeniaToken.mvc/Get" const val VULCAN_HEBE_ENDPOINT_REGISTER_NEW = "api/mobile/register/new" const val VULCAN_HEBE_ENDPOINT_MAIN = "api/mobile/register/hebe" +const val VULCAN_HEBE_ENDPOINT_TIMETABLE = "api/mobile/schedule" +const val VULCAN_HEBE_ENDPOINT_TIMETABLE_CHANGES = "api/mobile/schedule/changes" const val VULCAN_HEBE_ENDPOINT_EXAMS = "api/mobile/exam" const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade" const val VULCAN_HEBE_ENDPOINT_HOMEWORK = "api/mobile/homework" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt index 466f0dcf..0eef575a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt @@ -21,6 +21,7 @@ const val ENDPOINT_VULCAN_API_MESSAGES_INBOX = 1090 const val ENDPOINT_VULCAN_API_MESSAGES_SENT = 1100 const val ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS = 2010 const val ENDPOINT_VULCAN_HEBE_MAIN = 3000 +const val ENDPOINT_VULCAN_HEBE_TIMETABLE = 3020 const val ENDPOINT_VULCAN_HEBE_EXAMS = 3030 const val ENDPOINT_VULCAN_HEBE_GRADES = 3040 const val ENDPOINT_VULCAN_HEBE_HOMEWORK = 3060 @@ -30,6 +31,9 @@ val VulcanFeatures = listOf( Feature(LOGIN_TYPE_VULCAN, FEATURE_TIMETABLE, listOf( ENDPOINT_VULCAN_API_TIMETABLE to LOGIN_METHOD_VULCAN_API ), listOf(LOGIN_METHOD_VULCAN_API)), + Feature(LOGIN_TYPE_VULCAN, FEATURE_TIMETABLE, listOf( + ENDPOINT_VULCAN_HEBE_TIMETABLE to LOGIN_METHOD_VULCAN_HEBE + ), listOf(LOGIN_METHOD_VULCAN_HEBE)), // agenda Feature(LOGIN_TYPE_VULCAN, FEATURE_AGENDA, listOf( ENDPOINT_VULCAN_API_EVENTS to LOGIN_METHOD_VULCAN_API diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt index fb568815..f21f193d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt @@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeExams import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeGrades import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeHomework +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeTimetable import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.web.VulcanWebLuckyNumber import pl.szczodrzynski.edziennik.utils.Utils @@ -94,6 +95,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { data.startProgress(R.string.edziennik_progress_endpoint_lucky_number) VulcanWebLuckyNumber(data, lastSync, onSuccess) } + ENDPOINT_VULCAN_HEBE_TIMETABLE -> { + data.startProgress(R.string.edziennik_progress_endpoint_timetable) + VulcanHebeTimetable(data, lastSync, onSuccess) + } ENDPOINT_VULCAN_HEBE_EXAMS -> { data.startProgress(R.string.edziennik_progress_endpoint_exams) VulcanHebeExams(data, lastSync, onSuccess) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt index d8df2f8c..0d66f681 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt @@ -15,11 +15,13 @@ import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.HebeFilterType import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.db.entity.LessonRange import pl.szczodrzynski.edziennik.data.db.entity.Subject import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.data.db.entity.Team import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.models.Date +import pl.szczodrzynski.edziennik.utils.models.Time import java.net.HttpURLConnection import java.net.URLEncoder import java.time.Instant @@ -50,9 +52,9 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { return date.getString("Date")?.let { Date.fromY_m_d(it) } } - fun getTeacherId(json: JsonObject?, key: String): Long { + fun getTeacherId(json: JsonObject?, key: String): Long? { val teacher = json.getJsonObject(key) - val teacherId = teacher.getLong("Id") ?: return -1 + val teacherId = teacher.getLong("Id") ?: return null if (data.teacherList[teacherId] == null) { data.teacherList[teacherId] = Teacher( data.profileId, @@ -64,9 +66,9 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { return teacherId } - fun getSubjectId(json: JsonObject?, key: String): Long { + fun getSubjectId(json: JsonObject?, key: String): Long? { val subject = json.getJsonObject(key) - val subjectId = subject.getLong("Id") ?: return -1 + val subjectId = subject.getLong("Id") ?: return null if (data.subjectList[subjectId] == null) { data.subjectList[subjectId] = Subject( data.profileId, @@ -117,6 +119,21 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { return teamId } + fun getLessonRange(json: JsonObject?, key: String): LessonRange? { + val timeslot = json.getJsonObject(key) + val position = timeslot.getInt("Position") ?: return null + val start = timeslot.getString("Start") ?: return null + val end = timeslot.getString("End") ?: return null + val lessonRange = LessonRange( + data.profileId, + position, + Time.fromH_m(start), + Time.fromH_m(end) + ) + data.lessonRanges[position] = lessonRange + return lessonRange + } + fun getSemester(json: JsonObject?): Int { val periodId = json.getInt("PeriodId") ?: return 1 return if (periodId == data.semester1Id) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeExams.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeExams.kt index d5567780..54388a86 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeExams.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeExams.kt @@ -5,7 +5,6 @@ import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_EXAMS import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_EXAMS import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe -import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS @@ -29,8 +28,8 @@ class VulcanHebeExams( list.forEach { exam -> val id = exam.getLong("Id") ?: return@forEach val eventDate = getDate(exam, "Deadline") ?: return@forEach - val subjectId = getSubjectId(exam, "Subject") - val teacherId = getTeacherId(exam, "Creator") + val subjectId = getSubjectId(exam, "Subject") ?: -1 + val teacherId = getTeacherId(exam, "Creator") ?: -1 val teamId = getTeamId(exam, "Distribution") ?: getClassId(exam, "Class") ?: data.teamClass?.id @@ -72,7 +71,6 @@ class VulcanHebeExams( ) } - data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK)) data.setSyncNext(ENDPOINT_VULCAN_HEBE_EXAMS, SYNC_ALWAYS) onSuccess(ENDPOINT_VULCAN_HEBE_EXAMS) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt index 815f5ab1..11a7fdbc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt @@ -5,7 +5,6 @@ import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_GRADES import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_GRADES import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe -import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS @@ -35,8 +34,8 @@ class VulcanHebeGrades( val category = column.getJsonObject("Category") val categoryText = category.getString("Name") - val teacherId = getTeacherId(grade, "Creator") - val subjectId = getSubjectId(column, "Subject") + val teacherId = getTeacherId(grade, "Creator") ?: -1 + val subjectId = getSubjectId(column, "Subject") ?: -1 val description = column.getString("Name") val comment = grade.getString("Comment") @@ -115,10 +114,6 @@ class VulcanHebeGrades( ) } - data.toRemove.add( - DataRemoveModel.Grades.semesterWithType(data.studentSemesterNumber, - Grade.TYPE_NORMAL - )) data.setSyncNext(ENDPOINT_VULCAN_HEBE_GRADES, SYNC_ALWAYS) onSuccess(ENDPOINT_VULCAN_HEBE_GRADES) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeHomework.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeHomework.kt index 5e7f3e33..9ab8ede0 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeHomework.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeHomework.kt @@ -4,7 +4,6 @@ import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_HOMEWORK import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_HOMEWORK import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe -import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS @@ -30,8 +29,8 @@ class VulcanHebeHomework( list.forEach { exam -> val id = exam.getLong("IdHomework") ?: return@forEach val eventDate = getDate(exam, "Deadline") ?: return@forEach - val subjectId = getSubjectId(exam, "Subject") - val teacherId = getTeacherId(exam, "Creator") + val subjectId = getSubjectId(exam, "Subject") ?: -1 + val teacherId = getTeacherId(exam, "Creator") ?: -1 val teamId = data.teamClass?.id ?: -1 val topic = exam.getString("Content")?.trim() ?: "" @@ -63,7 +62,6 @@ class VulcanHebeHomework( ) } - data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK)) data.setSyncNext(ENDPOINT_VULCAN_HEBE_HOMEWORK, SYNC_ALWAYS) onSuccess(ENDPOINT_VULCAN_HEBE_HOMEWORK) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt new file mode 100644 index 00000000..99607fe8 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt @@ -0,0 +1,247 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe + +import com.google.gson.JsonObject +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_TIMETABLE +import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_TIMETABLE_CHANGES +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_TIMETABLE +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe +import pl.szczodrzynski.edziennik.data.db.entity.Lesson +import pl.szczodrzynski.edziennik.data.db.entity.Lesson.Companion.TYPE_CANCELLED +import pl.szczodrzynski.edziennik.data.db.entity.Lesson.Companion.TYPE_CHANGE +import pl.szczodrzynski.edziennik.data.db.entity.Lesson.Companion.TYPE_NORMAL +import pl.szczodrzynski.edziennik.data.db.entity.Lesson.Companion.TYPE_SHIFTED_SOURCE +import pl.szczodrzynski.edziennik.data.db.entity.Lesson.Companion.TYPE_SHIFTED_TARGET +import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.utils.Utils.d +import pl.szczodrzynski.edziennik.utils.models.Date +import pl.szczodrzynski.edziennik.utils.models.Week + +class VulcanHebeTimetable( + override val data: DataVulcan, + override val lastSync: Long?, + val onSuccess: (endpointId: Int) -> Unit +) : VulcanHebe(data, lastSync) { + companion object { + const val TAG = "VulcanHebeTimetable" + } + + private val lessonList = mutableListOf() + private val lessonDates = mutableSetOf() + + init { + val previousWeekStart = Week.getWeekStart().stepForward(0, 0, -7) + if (Date.getToday().weekDay > 4) { + previousWeekStart.stepForward(0, 0, 7) + } + + val dateFrom = data.arguments + ?.getString("weekStart") + ?.let { Date.fromY_m_d(it) } + ?: previousWeekStart + val dateTo = dateFrom.clone().stepForward(0, 0, 13) + + val lastSync = null + + apiGetList( + TAG, + VULCAN_HEBE_ENDPOINT_TIMETABLE, + HebeFilterType.BY_PUPIL, + dateFrom = dateFrom, + dateTo = dateTo, + lastSync = lastSync + ) { lessons, _ -> + apiGetList( + TAG, + VULCAN_HEBE_ENDPOINT_TIMETABLE_CHANGES, + HebeFilterType.BY_PUPIL, + dateFrom = dateFrom, + dateTo = dateTo, + lastSync = lastSync + ) { changes, _ -> + processData(lessons, changes) + + // cancel lesson changes when caused by a shift + for (lesson in lessonList) { + if (lesson.type != TYPE_SHIFTED_TARGET) + continue + lessonList.firstOrNull { + it.oldDate == lesson.date + && it.oldLessonNumber == lesson.lessonNumber + && it.type == TYPE_CHANGE + }?.let { + it.type = TYPE_CANCELLED + it.date = null + it.lessonNumber = null + it.startTime = null + it.endTime = null + it.subjectId = null + it.teacherId = null + it.teamId = null + it.classroom = null + } + } + + // add TYPE_NO_LESSONS to empty dates + val date: Date = dateFrom.clone() + while (date <= dateTo) { + if (!lessonDates.contains(date.value)) { + lessonList.add(Lesson(profileId, date.value.toLong()).apply { + this.type = Lesson.TYPE_NO_LESSONS + this.date = date.clone() + }) + } + + date.stepForward(0, 0, 1) + } + + d( + TAG, + "Clearing lessons between ${dateFrom.stringY_m_d} and ${dateTo.stringY_m_d}" + ) + + data.lessonList.addAll(lessonList) + + data.setSyncNext(ENDPOINT_VULCAN_HEBE_TIMETABLE, SYNC_ALWAYS) + onSuccess(ENDPOINT_VULCAN_HEBE_TIMETABLE) + } + } + } + + private fun buildLesson(changes: List, json: JsonObject): Pair? { + val lesson = Lesson(profileId, -1) + var lessonShift: Lesson? = null + + val lessonDate = getDate(json, "Date") ?: return null + val lessonRange = getLessonRange(json, "TimeSlot") + val startTime = lessonRange?.startTime + val endTime = lessonRange?.endTime + val teacherId = getTeacherId(json, "TeacherPrimary") + val classroom = json.getString("Room") + val subjectId = getSubjectId(json, "Subject") + + val teamId = getTeamId(json, "Distribution") + ?: getClassId(json, "Clazz") + ?: data.teamClass?.id + ?: -1 + + val change = json.getJsonObject("Change") + val changeId = change.getInt("Id") + val type = when (change.getInt("Type")) { + 1 -> TYPE_CANCELLED + 2 -> TYPE_CHANGE + 3 -> TYPE_SHIFTED_SOURCE + 4 -> TYPE_CANCELLED // TODO: 2021-02-21 add showing cancellation reason + else -> TYPE_NORMAL + } + + lesson.type = type + if (type == TYPE_NORMAL) { + lesson.date = lessonDate + lesson.lessonNumber = lessonRange?.lessonNumber + lesson.startTime = startTime + lesson.endTime = endTime + lesson.subjectId = subjectId + lesson.teacherId = teacherId + lesson.teamId = teamId + lesson.classroom = classroom + } else { + lesson.oldDate = lessonDate + lesson.oldLessonNumber = lessonRange?.lessonNumber + lesson.oldStartTime = startTime + lesson.oldEndTime = endTime + lesson.oldSubjectId = subjectId + lesson.oldTeacherId = teacherId + lesson.oldTeamId = teamId + lesson.oldClassroom = classroom + } + + if (type == TYPE_CHANGE || type == TYPE_SHIFTED_SOURCE) { + val changeJson = changes.firstOrNull { + it.getInt("Id") == changeId + } ?: return lesson to null + + val changeLessonDate = getDate(changeJson, "LessonDate") ?: return lesson to null + val changeLessonRange = getLessonRange(changeJson, "TimeSlot") ?: lessonRange + val changeStartTime = changeLessonRange?.startTime + val changeEndTime = changeLessonRange?.endTime + val changeTeacherId = getTeacherId(changeJson, "TeacherPrimary") ?: teacherId + val changeClassroom = changeJson.getString("Room") ?: classroom + val changeSubjectId = getSubjectId(changeJson, "Subject") ?: subjectId + + val changeTeamId = getTeamId(json, "Distribution") + ?: getClassId(json, "Clazz") + ?: teamId + + if (type != TYPE_CHANGE) { + /* lesson shifted */ + lessonShift = Lesson(profileId, -1) + lessonShift.type = TYPE_SHIFTED_TARGET + + // update source lesson with the target lesson date + lesson.date = changeLessonDate + lesson.lessonNumber = changeLessonRange?.lessonNumber + lesson.startTime = changeStartTime + lesson.endTime = changeEndTime + // update target lesson with the source lesson date + lessonShift.oldDate = lessonDate + lessonShift.oldLessonNumber = lessonRange?.lessonNumber + lessonShift.oldStartTime = startTime + lessonShift.oldEndTime = endTime + } + + (if (type == TYPE_CHANGE) lesson else lessonShift) + ?.apply { + this.date = changeLessonDate + this.lessonNumber = changeLessonRange?.lessonNumber + this.startTime = changeStartTime + this.endTime = changeEndTime + this.subjectId = changeSubjectId + this.teacherId = changeTeacherId + this.teamId = changeTeamId + this.classroom = changeClassroom + } + } + + return lesson to lessonShift + } + + private fun processData(lessons: List, changes: List) { + lessons.forEach { lessonJson -> + if (lessonJson.getBoolean("Visible") != true) + return@forEach + + val lessonPair = buildLesson(changes, lessonJson) ?: return@forEach + val (lessonObject, lessonShift) = lessonPair + + when { + lessonShift != null -> lessonShift + lessonObject.type != TYPE_NORMAL -> lessonObject + else -> null + }?.let { lesson -> + val lessonDate = lesson.displayDate ?: return@let + val seen = profile?.empty ?: true || lessonDate < Date.getToday() + data.metadataList.add( + Metadata( + profileId, + Metadata.TYPE_LESSON_CHANGE, + lesson.id, + seen, + seen + ) + ) + } + + lessonObject.id = lessonObject.buildId() + lessonShift?.id = lessonShift?.buildId() ?: -1 + + lessonList.add(lessonObject) + lessonShift?.let { lessonList.add(it) } + + lessonObject.displayDate?.let { lessonDates.add(it.value) } + lessonShift?.displayDate?.let { lessonDates.add(it.value) } + } + } +} From 1814fd67e16d8a154018c82c45592b1059454dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 16:39:02 +0100 Subject: [PATCH 11/24] [Strings] Update copyright date. --- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-en/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 461bdbd3..6e37bf58 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -854,7 +854,7 @@ Open-Source-Lizenzen Datenschutzrichtlinie E-Klassenbuch - © Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - 2020 + © Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - Februar 2021 Klicken Sie hier, um nach Aktualisierungen zu suchen Aktualisierung Version diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index f4a89910..ab80b93c 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -856,7 +856,7 @@ Open-source licenses Privacy policy E-register - © Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - 2020 + © Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - February 2021 Click to check for updates Update Version diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 40f79aa9..a913914d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -919,7 +919,7 @@ Licencje open-source Polityka prywatności E-dziennik - © Kuba Szczodrzyński && Kacper Ziubryniewicz\nwrzesień 2018 - 2020 + © Kuba Szczodrzyński && Kacper Ziubryniewicz\nwrzesień 2018 - luty 2021 Kliknij, aby sprawdzić aktualizacje Aktualizacja Wersja From 3f36a284eea3939ff6d40ea559b3419cae147a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 16:40:40 +0100 Subject: [PATCH 12/24] [4.5-beta.1] Update build.gradle, signing and changelog. --- app/src/main/assets/pl-changelog.html | 8 +++----- app/src/main/cpp/szkolny-signing.cpp | 2 +- .../edziennik/data/api/szkolny/interceptor/Signing.kt | 2 +- build.gradle | 4 ++-- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/src/main/assets/pl-changelog.html b/app/src/main/assets/pl-changelog.html index 50650cdd..f874f195 100644 --- a/app/src/main/assets/pl-changelog.html +++ b/app/src/main/assets/pl-changelog.html @@ -1,10 +1,8 @@ -

Wersja 4.4.3, 2020-10-16

+

Wersja 4.5-beta.1, 2021-02-21

    -
  • Mobidziennik: naprawione wysyłanie wiadomości.
  • -
  • Vulcan: naprawione logowanie dla dzienników w Koszalinie.
  • -
  • PPE: opcja wylogowania innych urządzeń przy logowaniu.
  • +
  • Vulcan: aplikacja Szkolny.eu zaktualizowana w związku z wygaszeniem aplikacji Dzienniczek+.


Dzięki za korzystanie ze Szkolnego!
-© Kuba Szczodrzyński, Kacper Ziubryniewicz 2020 +© Kuba Szczodrzyński, Kacper Ziubryniewicz 2021 diff --git a/app/src/main/cpp/szkolny-signing.cpp b/app/src/main/cpp/szkolny-signing.cpp index 4861d399..e3e83dc8 100644 --- a/app/src/main/cpp/szkolny-signing.cpp +++ b/app/src/main/cpp/szkolny-signing.cpp @@ -9,7 +9,7 @@ /*secret password - removed for source code publication*/ static toys AES_IV[16] = { - 0xaa, 0x6d, 0x87, 0x46, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + 0x35, 0x4c, 0x9d, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat); diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt index f8ca5090..0adf1fbd 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt @@ -46,6 +46,6 @@ object Signing { /*fun provideKey(param1: String, param2: Long): ByteArray {*/ fun pleaseStopRightNow(param1: String, param2: Long): ByteArray { - return "$param1.MTIzNDU2Nzg5MDzyYb9Lof===.$param2".sha256() + return "$param1.MTIzNDU2Nzg5MDQLA8n9Ff===.$param2".sha256() } } diff --git a/build.gradle b/build.gradle index 3b24a9a9..8e776f3d 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { kotlin_version = '1.4.30' release = [ - versionName: "4.4.3", - versionCode: 4040399 + versionName: "4.5-beta.1", + versionCode: 4050001 ] setup = [ From a9eda087e04f528d30376200a7697d9946cbfb85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 17:20:13 +0100 Subject: [PATCH 13/24] [Extensions] Update Gson extensions to check type. --- .../pl/szczodrzynski/edziennik/Extensions.kt | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt index f9e9d474..d4c6a2e0 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt @@ -96,30 +96,30 @@ fun List.byNameFDotSpaceLast(nameFDotSpaceLast: String) = firstOrNull { fun JsonObject?.get(key: String): JsonElement? = this?.get(key) -fun JsonObject?.getBoolean(key: String): Boolean? = get(key)?.let { if (it.isJsonNull) null else it.asBoolean } -fun JsonObject?.getString(key: String): String? = get(key)?.let { if (it.isJsonNull) null else it.asString } -fun JsonObject?.getInt(key: String): Int? = get(key)?.let { if (it.isJsonNull) null else it.asInt } -fun JsonObject?.getLong(key: String): Long? = get(key)?.let { if (it.isJsonNull) null else it.asLong } -fun JsonObject?.getFloat(key: String): Float? = get(key)?.let { if(it.isJsonNull) null else it.asFloat } -fun JsonObject?.getChar(key: String): Char? = get(key)?.let { if(it.isJsonNull) null else it.asCharacter } +fun JsonObject?.getBoolean(key: String): Boolean? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asBoolean } +fun JsonObject?.getString(key: String): String? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asString } +fun JsonObject?.getInt(key: String): Int? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asInt } +fun JsonObject?.getLong(key: String): Long? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asLong } +fun JsonObject?.getFloat(key: String): Float? = get(key)?.let { if(!it.isJsonPrimitive) null else it.asFloat } +fun JsonObject?.getChar(key: String): Char? = get(key)?.let { if(!it.isJsonPrimitive) null else it.asCharacter } fun JsonObject?.getJsonObject(key: String): JsonObject? = get(key)?.let { if (it.isJsonObject) it.asJsonObject else null } fun JsonObject?.getJsonArray(key: String): JsonArray? = get(key)?.let { if (it.isJsonArray) it.asJsonArray else null } -fun JsonObject?.getBoolean(key: String, defaultValue: Boolean): Boolean = get(key)?.let { if (it.isJsonNull) defaultValue else it.asBoolean } ?: defaultValue -fun JsonObject?.getString(key: String, defaultValue: String): String = get(key)?.let { if (it.isJsonNull) defaultValue else it.asString } ?: defaultValue -fun JsonObject?.getInt(key: String, defaultValue: Int): Int = get(key)?.let { if (it.isJsonNull) defaultValue else it.asInt } ?: defaultValue -fun JsonObject?.getLong(key: String, defaultValue: Long): Long = get(key)?.let { if (it.isJsonNull) defaultValue else it.asLong } ?: defaultValue -fun JsonObject?.getFloat(key: String, defaultValue: Float): Float = get(key)?.let { if(it.isJsonNull) defaultValue else it.asFloat } ?: defaultValue -fun JsonObject?.getChar(key: String, defaultValue: Char): Char = get(key)?.let { if(it.isJsonNull) defaultValue else it.asCharacter } ?: defaultValue +fun JsonObject?.getBoolean(key: String, defaultValue: Boolean): Boolean = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asBoolean } ?: defaultValue +fun JsonObject?.getString(key: String, defaultValue: String): String = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asString } ?: defaultValue +fun JsonObject?.getInt(key: String, defaultValue: Int): Int = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asInt } ?: defaultValue +fun JsonObject?.getLong(key: String, defaultValue: Long): Long = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asLong } ?: defaultValue +fun JsonObject?.getFloat(key: String, defaultValue: Float): Float = get(key)?.let { if(!it.isJsonPrimitive) defaultValue else it.asFloat } ?: defaultValue +fun JsonObject?.getChar(key: String, defaultValue: Char): Char = get(key)?.let { if(!it.isJsonPrimitive) defaultValue else it.asCharacter } ?: defaultValue fun JsonObject?.getJsonObject(key: String, defaultValue: JsonObject): JsonObject = get(key)?.let { if (it.isJsonObject) it.asJsonObject else defaultValue } ?: defaultValue fun JsonObject?.getJsonArray(key: String, defaultValue: JsonArray): JsonArray = get(key)?.let { if (it.isJsonArray) it.asJsonArray else defaultValue } ?: defaultValue -fun JsonArray.getBoolean(key: Int): Boolean? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asBoolean } -fun JsonArray.getString(key: Int): String? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asString } -fun JsonArray.getInt(key: Int): Int? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asInt } -fun JsonArray.getLong(key: Int): Long? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asLong } -fun JsonArray.getFloat(key: Int): Float? = if (key >= size()) null else get(key)?.let { if(it.isJsonNull) null else it.asFloat } -fun JsonArray.getChar(key: Int): Char? = if (key >= size()) null else get(key)?.let { if(it.isJsonNull) null else it.asCharacter } +fun JsonArray.getBoolean(key: Int): Boolean? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asBoolean } +fun JsonArray.getString(key: Int): String? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asString } +fun JsonArray.getInt(key: Int): Int? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asInt } +fun JsonArray.getLong(key: Int): Long? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asLong } +fun JsonArray.getFloat(key: Int): Float? = if (key >= size()) null else get(key)?.let { if(!it.isJsonPrimitive) null else it.asFloat } +fun JsonArray.getChar(key: Int): Char? = if (key >= size()) null else get(key)?.let { if(!it.isJsonPrimitive) null else it.asCharacter } fun JsonArray.getJsonObject(key: Int): JsonObject? = if (key >= size()) null else get(key)?.let { if (it.isJsonObject) it.asJsonObject else null } fun JsonArray.getJsonArray(key: Int): JsonArray? = if (key >= size()) null else get(key)?.let { if (it.isJsonArray) it.asJsonArray else null } From 8fc57cd3f5567f0f4e9e40ddb8dcc5374216b2d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 17:22:21 +0100 Subject: [PATCH 14/24] [Vulcan/Hebe] Fix getting classroom name. --- .../api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt index 99607fe8..48d06018 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt @@ -119,7 +119,7 @@ class VulcanHebeTimetable( val startTime = lessonRange?.startTime val endTime = lessonRange?.endTime val teacherId = getTeacherId(json, "TeacherPrimary") - val classroom = json.getString("Room") + val classroom = json.getJsonObject("Room").getString("Code") val subjectId = getSubjectId(json, "Subject") val teamId = getTeamId(json, "Distribution") @@ -168,7 +168,7 @@ class VulcanHebeTimetable( val changeStartTime = changeLessonRange?.startTime val changeEndTime = changeLessonRange?.endTime val changeTeacherId = getTeacherId(changeJson, "TeacherPrimary") ?: teacherId - val changeClassroom = changeJson.getString("Room") ?: classroom + val changeClassroom = changeJson.getJsonObject("Room").getString("Code") ?: classroom val changeSubjectId = getSubjectId(changeJson, "Subject") ?: subjectId val changeTeamId = getTeamId(json, "Distribution") From f49e39e85809d8401ab1e0a9cf8777e5573624c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 19:13:47 +0100 Subject: [PATCH 15/24] [Vulcan/Hebe] Add getting teacher list and addressbook. --- .../edziennik/data/api/Constants.kt | 1 + .../api/edziennik/vulcan/VulcanFeatures.kt | 7 +- .../api/edziennik/vulcan/data/VulcanData.kt | 22 +++- .../vulcan/data/hebe/VulcanHebeAddressbook.kt | 118 ++++++++++++++++++ .../vulcan/data/hebe/VulcanHebeMain.kt | 2 +- 5 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAddressbook.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index e5d8b7b6..8a518386 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -129,6 +129,7 @@ const val VULCAN_HEBE_ENDPOINT_REGISTER_NEW = "api/mobile/register/new" const val VULCAN_HEBE_ENDPOINT_MAIN = "api/mobile/register/hebe" const val VULCAN_HEBE_ENDPOINT_TIMETABLE = "api/mobile/schedule" const val VULCAN_HEBE_ENDPOINT_TIMETABLE_CHANGES = "api/mobile/schedule/changes" +const val VULCAN_HEBE_ENDPOINT_ADDRESSBOOK = "api/mobile/addressbook" const val VULCAN_HEBE_ENDPOINT_EXAMS = "api/mobile/exam" const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade" const val VULCAN_HEBE_ENDPOINT_HOMEWORK = "api/mobile/homework" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt index 0eef575a..d4749729 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt @@ -21,6 +21,7 @@ const val ENDPOINT_VULCAN_API_MESSAGES_INBOX = 1090 const val ENDPOINT_VULCAN_API_MESSAGES_SENT = 1100 const val ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS = 2010 const val ENDPOINT_VULCAN_HEBE_MAIN = 3000 +const val ENDPOINT_VULCAN_HEBE_ADDRESSBOOK = 3010 const val ENDPOINT_VULCAN_HEBE_TIMETABLE = 3020 const val ENDPOINT_VULCAN_HEBE_EXAMS = 3030 const val ENDPOINT_VULCAN_HEBE_GRADES = 3040 @@ -89,7 +90,11 @@ val VulcanFeatures = listOf( Feature(LOGIN_TYPE_VULCAN, FEATURE_ALWAYS_NEEDED, listOf( ENDPOINT_VULCAN_API_UPDATE_SEMESTER to LOGIN_METHOD_VULCAN_API, ENDPOINT_VULCAN_API_DICTIONARIES to LOGIN_METHOD_VULCAN_API - ), listOf(LOGIN_METHOD_VULCAN_API)) + ), listOf(LOGIN_METHOD_VULCAN_API)), + Feature(LOGIN_TYPE_VULCAN, FEATURE_ALWAYS_NEEDED, listOf( + ENDPOINT_VULCAN_HEBE_MAIN to LOGIN_METHOD_VULCAN_HEBE, + ENDPOINT_VULCAN_HEBE_ADDRESSBOOK to LOGIN_METHOD_VULCAN_HEBE + ), listOf(LOGIN_METHOD_VULCAN_HEBE)) /*Feature(LOGIN_TYPE_VULCAN, FEATURE_STUDENT_INFO, listOf( ENDPOINT_VULCAN_API to LOGIN_METHOD_VULCAN_WEB ), listOf(LOGIN_METHOD_VULCAN_WEB)), diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt index f21f193d..fd32db8a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt @@ -7,10 +7,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.* -import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeExams -import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeGrades -import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeHomework -import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeTimetable +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.web.VulcanWebLuckyNumber import pl.szczodrzynski.edziennik.utils.Utils @@ -95,6 +92,23 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { data.startProgress(R.string.edziennik_progress_endpoint_lucky_number) VulcanWebLuckyNumber(data, lastSync, onSuccess) } + ENDPOINT_VULCAN_HEBE_MAIN -> { + if (data.profile == null) { + onSuccess(ENDPOINT_VULCAN_HEBE_MAIN) + return + } + data.startProgress(R.string.edziennik_progress_endpoint_student_info) + VulcanHebeMain(data, lastSync).getStudents( + profile = data.profile, + profileList = null + ) { + onSuccess(ENDPOINT_VULCAN_HEBE_MAIN) + } + } + ENDPOINT_VULCAN_HEBE_ADDRESSBOOK -> { + data.startProgress(R.string.edziennik_progress_endpoint_teachers) + VulcanHebeAddressbook(data, lastSync, onSuccess) + } ENDPOINT_VULCAN_HEBE_TIMETABLE -> { data.startProgress(R.string.edziennik_progress_endpoint_timetable) VulcanHebeTimetable(data, lastSync, onSuccess) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAddressbook.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAddressbook.kt new file mode 100644 index 00000000..c96142aa --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAddressbook.kt @@ -0,0 +1,118 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe + +import androidx.core.util.set +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_ADDRESSBOOK +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_ADDRESSBOOK +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe +import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_EDUCATOR +import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_OTHER +import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_PARENT +import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_PARENTS_COUNCIL +import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_STUDENT +import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_TEACHER +import kotlin.text.replace + +class VulcanHebeAddressbook( + override val data: DataVulcan, + override val lastSync: Long?, + val onSuccess: (endpointId: Int) -> Unit +) : VulcanHebe(data, lastSync) { + companion object { + const val TAG = "VulcanHebeAddressbook" + } + + private fun String.removeUnitName(unitName: String?): String { + return (unitName ?: data.schoolShort)?.let { + this.replace("($it)", "").trim() + } ?: this + } + + init { + apiGetList( + TAG, + VULCAN_HEBE_ENDPOINT_ADDRESSBOOK, + HebeFilterType.BY_PERSON, + lastSync = lastSync, + includeFilterType = false + ) { list, _ -> + list.forEach { person -> + val id = person.getString("Id") ?: return@forEach + val loginId = person.getString("LoginId") ?: return@forEach + + val idType = id.split("-") + .getOrNull(0) + val idLong = id.split("-") + .getOrNull(1) + ?.toLongOrNull() + ?: return@forEach + + val typeBase = when (idType) { + "e" -> TYPE_TEACHER + "c" -> TYPE_PARENT + "p" -> TYPE_STUDENT + else -> TYPE_OTHER + } + + val name = person.getString("Name") ?: "" + val surname = person.getString("Surname") ?: "" + val namePrefix = "$surname $name - " + + val teacher = data.teacherList[idLong] ?: Teacher( + data.profileId, + idLong, + name, + surname, + loginId + ).also { + data.teacherList[idLong] = it + } + + person.getJsonArray("Roles")?.asJsonObjectList()?.onEach { role -> + var roleText: String? = null + val unitName = role.getString("ConstituentUnitSymbol") + + val personType = when (role.getInt("RoleOrder")) { + 0 -> { /* Wychowawca */ + roleText = role.getString("ClassSymbol") + ?.removeUnitName(unitName) + TYPE_EDUCATOR + } + 1 -> TYPE_TEACHER /* Nauczyciel */ + 2 -> return@onEach /* Pracownik */ + 3 -> { /* Rada rodziców */ + roleText = role.getString("Address") + ?.removeUnitName(unitName) + ?.removePrefix(namePrefix) + ?.trim() + TYPE_PARENTS_COUNCIL + } + 5 -> { + roleText = role.getString("RoleName") + ?.plus(" - ") + ?.plus( + role.getString("Address") + ?.removeUnitName(unitName) + ?.removePrefix(namePrefix) + ?.trim() + ) + TYPE_STUDENT + } + else -> TYPE_OTHER + } + + teacher.setTeacherType(personType) + teacher.typeDescription = roleText + } + + if (teacher.type == 0) + teacher.setTeacherType(typeBase) + } + + data.setSyncNext(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK, 2 * DAY) + onSuccess(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK) + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt index 020509c3..b3d88d04 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt @@ -76,7 +76,7 @@ class VulcanHebeMain( } val schoolSymbol = unit.getString("Symbol") ?: return@forEach - val schoolShort = unit.getString("Short") ?: return@forEach + val schoolShort = constituentUnit.getString("Short") ?: return@forEach val schoolCode = "${data.symbol}_$schoolSymbol" val studentUnitId = unit.getInt("Id") ?: return@forEach From e86b47fb1b736371b85381f6cb22981bea7e8d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 21:50:44 +0100 Subject: [PATCH 16/24] [Vulcan/Hebe] Add getting messages. --- .../edziennik/data/api/Constants.kt | 1 + .../data/api/edziennik/vulcan/Vulcan.kt | 14 ++ .../api/edziennik/vulcan/VulcanFeatures.kt | 8 ++ .../api/edziennik/vulcan/data/VulcanData.kt | 9 ++ .../api/edziennik/vulcan/data/VulcanHebe.kt | 4 +- .../vulcan/data/hebe/VulcanHebeMessages.kt | 127 ++++++++++++++++++ 6 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessages.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index 8a518386..d44aa78a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -133,6 +133,7 @@ const val VULCAN_HEBE_ENDPOINT_ADDRESSBOOK = "api/mobile/addressbook" const val VULCAN_HEBE_ENDPOINT_EXAMS = "api/mobile/exam" const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade" const val VULCAN_HEBE_ENDPOINT_HOMEWORK = "api/mobile/homework" +const val VULCAN_HEBE_ENDPOINT_MESSAGES = "api/mobile/message" const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt index 9761343c..ef19638c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt @@ -91,6 +91,20 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va } override fun getMessage(message: MessageFull) { + if (loginStore.mode != LOGIN_MODE_VULCAN_API) { + login(LOGIN_METHOD_VULCAN_HEBE) { + if (message.seen) { + EventBus.getDefault().postSticky(MessageGetEvent(message)) + completed() + return@login + } + VulcanApiMessagesChangeStatus(data, message) { + completed() + } + } + return + } + login(LOGIN_METHOD_VULCAN_API) { if (message.attachmentIds != null) { VulcanApiMessagesChangeStatus(data, message) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt index d4749729..5b8944f6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt @@ -26,6 +26,8 @@ const val ENDPOINT_VULCAN_HEBE_TIMETABLE = 3020 const val ENDPOINT_VULCAN_HEBE_EXAMS = 3030 const val ENDPOINT_VULCAN_HEBE_GRADES = 3040 const val ENDPOINT_VULCAN_HEBE_HOMEWORK = 3060 +const val ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX = 3090 +const val ENDPOINT_VULCAN_HEBE_MESSAGES_SENT = 3100 val VulcanFeatures = listOf( // timetable @@ -72,6 +74,12 @@ val VulcanFeatures = listOf( Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_SENT, listOf( ENDPOINT_VULCAN_API_MESSAGES_SENT to LOGIN_METHOD_VULCAN_API ), listOf(LOGIN_METHOD_VULCAN_API)), + Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_INBOX, listOf( + ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX to LOGIN_METHOD_VULCAN_HEBE + ), listOf(LOGIN_METHOD_VULCAN_HEBE)), + Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_SENT, listOf( + ENDPOINT_VULCAN_HEBE_MESSAGES_SENT to LOGIN_METHOD_VULCAN_HEBE + ), listOf(LOGIN_METHOD_VULCAN_HEBE)), // push config Feature(LOGIN_TYPE_VULCAN, FEATURE_PUSH_CONFIG, listOf( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt index fd32db8a..af15be8e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt @@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.web.VulcanWebLuckyNumber +import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.utils.Utils class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { @@ -125,6 +126,14 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { data.startProgress(R.string.edziennik_progress_endpoint_homework) VulcanHebeHomework(data, lastSync, onSuccess) } + ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX -> { + data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox) + VulcanHebeMessages(data, lastSync, onSuccess).getMessages(Message.TYPE_RECEIVED) + } + ENDPOINT_VULCAN_HEBE_MESSAGES_SENT -> { + data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox) + VulcanHebeMessages(data, lastSync, onSuccess).getMessages(Message.TYPE_SENT) + } else -> onSuccess(endpointId) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt index 0d66f681..304f24a1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt @@ -42,9 +42,9 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { val profile get() = data.profile - fun getDateTime(json: JsonObject?, key: String): Long { + fun getDateTime(json: JsonObject?, key: String, default: Long = System.currentTimeMillis()): Long { val date = json.getJsonObject(key) - return date.getLong("Timestamp") ?: return System.currentTimeMillis() + return date.getLong("Timestamp") ?: return default } fun getDate(json: JsonObject?, key: String): Date? { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessages.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessages.kt new file mode 100644 index 00000000..22fb39b7 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessages.kt @@ -0,0 +1,127 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe + +import androidx.core.util.set +import com.google.gson.JsonObject +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES +import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGES +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_MESSAGES_SENT +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe +import pl.szczodrzynski.edziennik.data.db.entity.* +import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_DELETED +import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED +import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT +import pl.szczodrzynski.navlib.crc16 +import kotlin.text.replace + +class VulcanHebeMessages( + override val data: DataVulcan, + override val lastSync: Long?, + val onSuccess: (endpointId: Int) -> Unit +) : VulcanHebe(data, lastSync) { + companion object { + const val TAG = "VulcanHebeMessagesInbox" + } + + private fun getPersonId(json: JsonObject): Long { + val senderLoginId = json.getInt("LoginId") ?: return -1 + /*if (senderLoginId == data.studentLoginId) + return -1*/ + + val senderName = json.getString("Address") ?: return -1 + val senderNameSplit = senderName.splitName() + val senderLoginIdStr = senderLoginId.toString() + val teacher = data.teacherList.singleOrNull { it.loginId == senderLoginIdStr } + ?: Teacher( + profileId, + -1 * crc16(senderName).toLong(), + senderNameSplit?.second ?: "", + senderNameSplit?.first ?: "", + senderLoginIdStr + ).also { + it.setTeacherType(Teacher.TYPE_OTHER) + data.teacherList[it.id] = it + } + return teacher.id + } + + fun getMessages(messageType: Int) { + val folder = when (messageType) { + TYPE_RECEIVED -> 1 + TYPE_SENT -> 2 + TYPE_DELETED -> 3 + else -> 1 + } + val endpointId = when (messageType) { + TYPE_RECEIVED -> ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX + TYPE_SENT -> ENDPOINT_VULCAN_HEBE_MESSAGES_SENT + else -> ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX + } + apiGetList( + TAG, + VULCAN_HEBE_ENDPOINT_MESSAGES, + HebeFilterType.BY_PERSON, + folder = folder, + lastSync = lastSync + ) { list, _ -> + list.forEach { message -> + val id = message.getLong("Id") ?: return@forEach + val subject = message.getString("Subject") ?: return@forEach + val body = message.getString("Content") ?: return@forEach + + val sender = message.getJsonObject("Sender") ?: return@forEach + + val sentDate = getDateTime(message, "DateSent") + val readDate = getDateTime(message, "DateRead", default = 0) + + val messageObject = Message( + profileId = profileId, + id = id, + type = messageType, + subject = subject, + body = body.replace("\n", "
"), + senderId = if (messageType == TYPE_RECEIVED) getPersonId(sender) else null, + addedDate = sentDate + ) + + val receivers = message.getJsonArray("Receiver") + ?.asJsonObjectList() + ?: return@forEach + val receiverReadDate = + if (receivers.size == 1) readDate + else -1 + + for (receiver in receivers) { + val messageRecipientObject = MessageRecipient( + profileId, + if (messageType == TYPE_SENT) getPersonId(receiver) else -1, + -1, + receiverReadDate, + id + ) + data.messageRecipientList.add(messageRecipientObject) + } + + data.messageList.add(messageObject) + data.setSeenMetadataList.add( + Metadata( + profileId, + Metadata.TYPE_MESSAGE, + id, + readDate > 0 || messageType == TYPE_SENT, + readDate > 0 || messageType == TYPE_SENT + ) + ) + } + + data.setSyncNext( + endpointId, + if (messageType == TYPE_RECEIVED) SYNC_ALWAYS else 1 * DAY, + if (messageType == TYPE_RECEIVED) null else DRAWER_ITEM_MESSAGES + ) + onSuccess(endpointId) + } + } +} From 621a7ac6426c18c5a7af3dbf089efb4be161e39e Mon Sep 17 00:00:00 2001 From: Kacper Ziubryniewicz Date: Sun, 21 Feb 2021 22:28:54 +0100 Subject: [PATCH 17/24] [Vulcan/Hebe] Add getting attendance. --- .../edziennik/data/api/Constants.kt | 1 + .../api/edziennik/vulcan/VulcanFeatures.kt | 4 + .../api/edziennik/vulcan/data/VulcanData.kt | 4 + .../vulcan/data/hebe/VulcanHebeAttendance.kt | 125 ++++++++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index d44aa78a..aac3f498 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -133,6 +133,7 @@ const val VULCAN_HEBE_ENDPOINT_ADDRESSBOOK = "api/mobile/addressbook" const val VULCAN_HEBE_ENDPOINT_EXAMS = "api/mobile/exam" const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade" const val VULCAN_HEBE_ENDPOINT_HOMEWORK = "api/mobile/homework" +const val VULCAN_HEBE_ENDPOINT_ATTENDANCE = "api/mobile/lesson" const val VULCAN_HEBE_ENDPOINT_MESSAGES = "api/mobile/message" const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt index 5b8944f6..9e247575 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt @@ -26,6 +26,7 @@ const val ENDPOINT_VULCAN_HEBE_TIMETABLE = 3020 const val ENDPOINT_VULCAN_HEBE_EXAMS = 3030 const val ENDPOINT_VULCAN_HEBE_GRADES = 3040 const val ENDPOINT_VULCAN_HEBE_HOMEWORK = 3060 +const val ENDPOINT_VULCAN_HEBE_ATTENDANCE = 3080 const val ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX = 3090 const val ENDPOINT_VULCAN_HEBE_MESSAGES_SENT = 3100 @@ -67,6 +68,9 @@ val VulcanFeatures = listOf( Feature(LOGIN_TYPE_VULCAN, FEATURE_ATTENDANCE, listOf( ENDPOINT_VULCAN_API_ATTENDANCE to LOGIN_METHOD_VULCAN_API ), listOf(LOGIN_METHOD_VULCAN_API)), + Feature(LOGIN_TYPE_VULCAN, FEATURE_ATTENDANCE, listOf( + ENDPOINT_VULCAN_HEBE_ATTENDANCE to LOGIN_METHOD_VULCAN_HEBE + ), listOf(LOGIN_METHOD_VULCAN_HEBE)), // messages Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_INBOX, listOf( ENDPOINT_VULCAN_API_MESSAGES_INBOX to LOGIN_METHOD_VULCAN_API diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt index af15be8e..6b733e33 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt @@ -134,6 +134,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox) VulcanHebeMessages(data, lastSync, onSuccess).getMessages(Message.TYPE_SENT) } + ENDPOINT_VULCAN_HEBE_ATTENDANCE -> { + data.startProgress(R.string.edziennik_progress_endpoint_attendance) + VulcanHebeAttendance(data, lastSync, onSuccess) + } else -> onSuccess(endpointId) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt new file mode 100644 index 00000000..c423d634 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt @@ -0,0 +1,125 @@ +/* + * Copyright (c) Kacper Ziubryniewicz 2021-2-21 + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe + +import com.google.gson.JsonObject +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_ATTENDANCE +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe +import pl.szczodrzynski.edziennik.data.db.entity.Attendance +import pl.szczodrzynski.edziennik.data.db.entity.Metadata + +class VulcanHebeAttendance( + override val data: DataVulcan, + override val lastSync: Long?, + val onSuccess: (endpointId: Int) -> Unit +) : VulcanHebe(data, lastSync) { + + companion object { + const val TAG = "VulcanHebeAttendance" + } + + init { + apiGetList( + TAG, + VULCAN_HEBE_ENDPOINT_ATTENDANCE, + HebeFilterType.BY_PUPIL, + lastSync = lastSync + ) { list, _ -> + list.forEach { attendance -> + val id = attendance.getLong("AuxPresenceId") ?: return@forEach + val type = attendance.getJsonObject("PresenceType") ?: return@forEach + val baseType = getBaseType(type) + val typeName = type.getString("Name") ?: return@forEach + val typeCategoryId = type.getLong("CategoryId") ?: return@forEach + val typeSymbol = type.getString("Symbol") ?: return@forEach + val typeShort = when (typeCategoryId.toInt()) { + 6, 8 -> typeSymbol + else -> data.app.attendanceManager.getTypeShort(baseType) + } + val typeColor = when (typeCategoryId.toInt()) { + 1 -> 0xffffffff // obecność + 2 -> 0xffffa687 // nieobecność + 3 -> 0xfffcc150 // nieobecność usprawiedliwiona + 4 -> 0xffede049 // spóźnienie + 5 -> 0xffbbdd5f // spóźnienie usprawiedliwione + 6 -> 0xffa9c9fd // nieobecny z przyczyn szkolnych + 7 -> 0xffddbbe5 // zwolniony + 8 -> 0xffffffff // usunięty wpis + else -> null + }?.toInt() + val date = getDate(attendance, "Day") ?: return@forEach + val lessonRange = getLessonRange(attendance, "TimeSlot") + val startTime = lessonRange?.startTime + val semester = profile?.dateToSemester(date) ?: return@forEach + val teacherId = attendance.getJsonObject("TeacherPrimary")?.getLong("Id") ?: -1 + val subjectId = attendance.getJsonObject("Subject")?.getLong("Id") ?: -1 + val addedDate = getDateTime(attendance, "DateModify") + val lessonNumber = lessonRange?.lessonNumber + val isCounted = attendance.getBoolean("CalculatePresence") + ?: (baseType != Attendance.TYPE_RELEASED) + + val attendanceObject = Attendance( + profileId = profileId, + id = id, + baseType = baseType, + typeName = typeName, + typeShort = typeShort, + typeSymbol = typeSymbol, + typeColor = typeColor, + date = date, + startTime = startTime, + semester = semester, + teacherId = teacherId, + subjectId = subjectId, + addedDate = addedDate + ).also { + it.lessonNumber = lessonNumber + it.isCounted = isCounted + } + + data.attendanceList.add(attendanceObject) + if (baseType != Attendance.TYPE_PRESENT) { + data.metadataList.add( + Metadata( + profileId, + Metadata.TYPE_ATTENDANCE, + attendanceObject.id, + profile?.empty ?: true || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN, + profile?.empty ?: true || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN + ) + ) + } + } + } + } + + fun getBaseType(attendanceType: JsonObject): Int { + val absent = attendanceType.getBoolean("Absence") ?: false + val excused = attendanceType.getBoolean("AbsenceJustified") ?: false + return if (absent) { + if (excused) + Attendance.TYPE_ABSENT_EXCUSED + else + Attendance.TYPE_ABSENT + } else { + val belated = attendanceType.getBoolean("Late") ?: false + val released = attendanceType.getBoolean("LegalAbsence") ?: false + val present = attendanceType.getBoolean("Presence") ?: true + if (belated) + if (excused) + Attendance.TYPE_BELATED_EXCUSED + else + Attendance.TYPE_BELATED + else if (released) + Attendance.TYPE_RELEASED + else if (present) + Attendance.TYPE_PRESENT + else + Attendance.TYPE_UNKNOWN + } + } +} From 6c0ddd3e6dd7919f0a79fec8fd85caa576b47b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 22:54:52 +0100 Subject: [PATCH 18/24] [Vulcan/Hebe] Add setting message status as read. --- .../edziennik/data/api/Constants.kt | 1 + .../data/api/edziennik/vulcan/Vulcan.kt | 3 +- .../api/edziennik/vulcan/data/VulcanHebe.kt | 7 ++- .../hebe/VulcanHebeMessagesChangeStatus.kt | 62 +++++++++++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessagesChangeStatus.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index aac3f498..614d5f3a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -135,6 +135,7 @@ const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade" const val VULCAN_HEBE_ENDPOINT_HOMEWORK = "api/mobile/homework" const val VULCAN_HEBE_ENDPOINT_ATTENDANCE = "api/mobile/lesson" const val VULCAN_HEBE_ENDPOINT_MESSAGES = "api/mobile/message" +const val VULCAN_HEBE_ENDPOINT_MESSAGES_STATUS = "api/mobile/message/status" const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt index ef19638c..9dfc1572 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt @@ -13,6 +13,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanData import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiAttachments import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiMessagesChangeStatus import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiSendMessage +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeMessagesChangeStatus import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.firstlogin.VulcanFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLogin import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent @@ -98,7 +99,7 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va completed() return@login } - VulcanApiMessagesChangeStatus(data, message) { + VulcanHebeMessagesChangeStatus(data, message) { completed() } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt index 304f24a1..c61140c4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt @@ -207,8 +207,9 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { } val envelope = when (T::class.java) { - JsonObject::class.java -> json.getJsonObject("Envelope") - JsonArray::class.java -> json.getJsonArray("Envelope") + JsonObject::class.java -> json.getJsonObject("Envelope") as T + JsonArray::class.java -> json.getJsonArray("Envelope") as T + java.lang.Boolean::class.java -> json.getBoolean("Envelope") as T else -> { data.error(ApiError(tag, ERROR_RESPONSE_EMPTY) .withResponse(response) @@ -219,7 +220,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { } try { - onSuccess(envelope as T, response) + onSuccess(envelope, response) } catch (e: Exception) { data.error(ApiError(tag, EXCEPTION_VULCAN_HEBE_REQUEST) .withResponse(response) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessagesChangeStatus.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessagesChangeStatus.kt new file mode 100644 index 00000000..74d3f759 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessagesChangeStatus.kt @@ -0,0 +1,62 @@ +package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe + +import org.greenrobot.eventbus.EventBus +import pl.szczodrzynski.edziennik.JsonObject +import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGES_STATUS +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe +import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent +import pl.szczodrzynski.edziennik.data.db.entity.Message +import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient +import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.full.MessageFull + +class VulcanHebeMessagesChangeStatus( + override val data: DataVulcan, + private val messageObject: MessageFull, + val onSuccess: () -> Unit +) : VulcanHebe(data, null) { + companion object { + const val TAG = "VulcanHebeMessagesChangeStatus" + } + + init { + apiPost( + TAG, + VULCAN_HEBE_ENDPOINT_MESSAGES_STATUS, + payload = JsonObject( + "MessageId" to messageObject.id, + "LoginId" to data.studentLoginId, + "Status" to 1 + ) + ) { _: Boolean, _ -> + + if (!messageObject.seen) { + data.setSeenMetadataList.add( + Metadata( + profileId, + Metadata.TYPE_MESSAGE, + messageObject.id, + true, + true + ) + ) + messageObject.seen = true + } + + if (messageObject.type != Message.TYPE_SENT) { + val messageRecipientObject = MessageRecipient( + profileId, + -1, + -1, + System.currentTimeMillis(), + messageObject.id + ) + data.messageRecipientList.add(messageRecipientObject) + } + + EventBus.getDefault().postSticky(MessageGetEvent(messageObject)) + onSuccess() + } + } +} From 5903bbe59df51eedc4c89e606c2a378fd37c2104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 23:03:06 +0100 Subject: [PATCH 19/24] [Vulcan/Hebe] Fix getting attendance. --- .../vulcan/data/hebe/VulcanHebeAttendance.kt | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt index c423d634..b1224334 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt @@ -8,9 +8,11 @@ import com.google.gson.JsonObject import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_ATTENDANCE import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_ATTENDANCE import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.db.entity.Attendance import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS class VulcanHebeAttendance( override val data: DataVulcan, @@ -23,10 +25,16 @@ class VulcanHebeAttendance( } init { + val semesterNumber = data.studentSemesterNumber + val startDate = profile?.getSemesterStart(semesterNumber) + val endDate = profile?.getSemesterEnd(semesterNumber) + apiGetList( TAG, VULCAN_HEBE_ENDPOINT_ATTENDANCE, HebeFilterType.BY_PUPIL, + dateFrom = startDate, + dateTo = endDate, lastSync = lastSync ) { list, _ -> list.forEach { attendance -> @@ -88,12 +96,19 @@ class VulcanHebeAttendance( profileId, Metadata.TYPE_ATTENDANCE, attendanceObject.id, - profile?.empty ?: true || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN, - profile?.empty ?: true || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN + profile?.empty ?: true + || baseType == Attendance.TYPE_PRESENT_CUSTOM + || baseType == Attendance.TYPE_UNKNOWN, + profile?.empty ?: true + || baseType == Attendance.TYPE_PRESENT_CUSTOM + || baseType == Attendance.TYPE_UNKNOWN ) ) } } + + data.setSyncNext(ENDPOINT_VULCAN_HEBE_ATTENDANCE, SYNC_ALWAYS) + onSuccess(ENDPOINT_VULCAN_HEBE_ATTENDANCE) } } From e869107101ec3c5c1ccdda316c545933f44c85c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 23:26:43 +0100 Subject: [PATCH 20/24] [Vulcan/Hebe] Add syncing both semesters during first sync. --- .../api/edziennik/vulcan/data/VulcanData.kt | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt index 6b733e33..02dfdc5b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt @@ -17,8 +17,30 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { private const val TAG = "VulcanData" } + private var firstSemesterSync = false + private val firstSemesterSyncExclude = listOf( + ENDPOINT_VULCAN_HEBE_MAIN, + ENDPOINT_VULCAN_HEBE_ADDRESSBOOK, + ENDPOINT_VULCAN_HEBE_TIMETABLE, + ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX, + ENDPOINT_VULCAN_HEBE_MESSAGES_SENT + ) + init { - nextEndpoint(onSuccess) + if (data.studentSemesterNumber == 2 && data.profile?.empty != false) { + firstSemesterSync = true + // set to sync 1st semester first + data.studentSemesterId = data.semester1Id + data.studentSemesterNumber = 1 + } + nextEndpoint { + if (firstSemesterSync) { + // at the end, set back 2nd semester + data.studentSemesterId = data.semester2Id + data.studentSemesterNumber = 2 + } + onSuccess() + } } private fun nextEndpoint(onSuccess: () -> Unit) { @@ -32,7 +54,21 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { } val id = data.targetEndpointIds.firstKey() val lastSync = data.targetEndpointIds.remove(id) - useEndpoint(id, lastSync) { endpointId -> + useEndpoint(id, lastSync) { + if (firstSemesterSync && id !in firstSemesterSyncExclude) { + // sync 2nd semester after every endpoint + data.studentSemesterId = data.semester2Id + data.studentSemesterNumber = 2 + useEndpoint(id, lastSync) { + // set 1st semester back for the next endpoint + data.studentSemesterId = data.semester1Id + data.studentSemesterNumber = 1 + // progress further + data.progress(data.progressStep) + nextEndpoint(onSuccess) + } + return@useEndpoint + } data.progress(data.progressStep) nextEndpoint(onSuccess) } From a11a44b7688754c4cb7a4a04788266085b5f9912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 23:30:20 +0100 Subject: [PATCH 21/24] [Vulcan/Hebe] Add handling custom presence types. --- .../api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt index b1224334..3d207388 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt @@ -132,7 +132,10 @@ class VulcanHebeAttendance( else if (released) Attendance.TYPE_RELEASED else if (present) - Attendance.TYPE_PRESENT + if (attendanceType.getInt("CategoryId") != 1) + Attendance.TYPE_PRESENT_CUSTOM + else + Attendance.TYPE_PRESENT else Attendance.TYPE_UNKNOWN } From 6aee3ea42026b98f9e45f08abffc1388fa1b1314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 23:36:55 +0100 Subject: [PATCH 22/24] [4.5-beta.2] Update build.gradle, signing and changelog. --- app/src/main/assets/pl-changelog.html | 2 +- app/src/main/cpp/szkolny-signing.cpp | 2 +- .../edziennik/data/api/szkolny/interceptor/Signing.kt | 2 +- build.gradle | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/assets/pl-changelog.html b/app/src/main/assets/pl-changelog.html index f874f195..165582ec 100644 --- a/app/src/main/assets/pl-changelog.html +++ b/app/src/main/assets/pl-changelog.html @@ -1,4 +1,4 @@ -

Wersja 4.5-beta.1, 2021-02-21

+

Wersja 4.5-beta.2, 2021-02-21

  • Vulcan: aplikacja Szkolny.eu zaktualizowana w związku z wygaszeniem aplikacji Dzienniczek+.
diff --git a/app/src/main/cpp/szkolny-signing.cpp b/app/src/main/cpp/szkolny-signing.cpp index e3e83dc8..b2b15406 100644 --- a/app/src/main/cpp/szkolny-signing.cpp +++ b/app/src/main/cpp/szkolny-signing.cpp @@ -9,7 +9,7 @@ /*secret password - removed for source code publication*/ static toys AES_IV[16] = { - 0x35, 0x4c, 0x9d, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + 0x42, 0xf5, 0x8e, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat); diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt index 0adf1fbd..b15b6408 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt @@ -46,6 +46,6 @@ object Signing { /*fun provideKey(param1: String, param2: Long): ByteArray {*/ fun pleaseStopRightNow(param1: String, param2: Long): ByteArray { - return "$param1.MTIzNDU2Nzg5MDQLA8n9Ff===.$param2".sha256() + return "$param1.MTIzNDU2Nzg5MDL9U0lwJn===.$param2".sha256() } } diff --git a/build.gradle b/build.gradle index 8e776f3d..54a6a31b 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { kotlin_version = '1.4.30' release = [ - versionName: "4.5-beta.1", - versionCode: 4050001 + versionName: "4.5-beta.2", + versionCode: 4050002 ] setup = [ From 80333cdea4193503d00f75ec838cd923f0cc5793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 23:52:45 +0100 Subject: [PATCH 23/24] [Vulcan] Add API deprecation message. --- .../java/pl/szczodrzynski/edziennik/MainActivity.kt | 5 +++++ .../java/pl/szczodrzynski/edziennik/data/api/Errors.kt | 1 + .../data/api/edziennik/vulcan/data/VulcanData.kt | 10 ++++++++-- app/src/main/res/values/errors.xml | 2 ++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index 0bbc77f7..d5a1adde 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -38,6 +38,7 @@ import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import pl.droidsonroids.gif.GifDrawable +import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.events.* import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -64,6 +65,7 @@ import pl.szczodrzynski.edziennik.ui.modules.base.MainSnackbar import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment import pl.szczodrzynski.edziennik.ui.modules.debug.DebugFragment import pl.szczodrzynski.edziennik.ui.modules.debug.LabFragment +import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDetailsDialog import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment @@ -756,6 +758,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope { } mainSnackbar.dismiss() errorSnackbar.addError(event.error).show() + if (event.error.errorCode == ERROR_VULCAN_API_DEPRECATED) { + ErrorDetailsDialog(this, listOf(event.error)) + } } @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) fun onAppManagerDetectedEvent(event: AppManagerDetectedEvent) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt index c7a47e24..6809ed2e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt @@ -171,6 +171,7 @@ const val ERROR_VULCAN_WEB_CERTIFICATE_POST_FAILED = 351 const val ERROR_VULCAN_WEB_GRADUATE_ACCOUNT = 352 const val ERROR_VULCAN_WEB_NO_SCHOOLS = 353 const val ERROR_VULCAN_HEBE_OTHER = 354 +const val ERROR_VULCAN_API_DEPRECATED = 390 const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN = 401 const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME = 402 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt index 02dfdc5b..2fc21190 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt @@ -5,6 +5,8 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED +import pl.szczodrzynski.edziennik.data.api.LOGIN_MODE_VULCAN_API import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.* @@ -26,7 +28,11 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { ENDPOINT_VULCAN_HEBE_MESSAGES_SENT ) - init { + init { run { + if (data.loginStore.mode == LOGIN_MODE_VULCAN_API) { + data.error(TAG, ERROR_VULCAN_API_DEPRECATED) + return@run + } if (data.studentSemesterNumber == 2 && data.profile?.empty != false) { firstSemesterSync = true // set to sync 1st semester first @@ -41,7 +47,7 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { } onSuccess() } - } + }} private fun nextEndpoint(onSuccess: () -> Unit) { if (data.targetEndpointIds.isEmpty()) { diff --git a/app/src/main/res/values/errors.xml b/app/src/main/res/values/errors.xml index 3e5f48d6..91fae735 100644 --- a/app/src/main/res/values/errors.xml +++ b/app/src/main/res/values/errors.xml @@ -130,6 +130,7 @@ ERROR_VULCAN_API_BAD_REQUEST ERROR_VULCAN_API_OTHER ERROR_VULCAN_ATTACHMENT_DOWNLOAD + ERROR_VULCAN_API_DEPRECATED ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME @@ -318,6 +319,7 @@ VULCAN®: błąd żądania, zgłoś błąd VULCAN®: inny błąd, wyślij zgłoszenie VULCAN®: nie znaleziono adresu załącznika + W związku z wygaszeniem aplikacji Dzienniczek+ przez firmę Vulcan, należy zalogować się ponownie.\n\nAby móc dalej korzystać z aplikacji Szkolny.eu, otwórz Ustawienia i wybierz opcję Dodaj nowego ucznia.\nNastępnie zaloguj się do dziennika Vulcan zgodnie z instrukcją.\n\nPrzepraszamy za niedogodności. Nieprawidłowe dane logowania Nieprawidłowa nazwa szkoły From c27254bcad1f41368f1ba2f00cb84984f3447354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 21 Feb 2021 23:55:11 +0100 Subject: [PATCH 24/24] [Vulcan] Remove API login mode form. --- .../edziennik/ui/modules/login/LoginInfo.kt | 54 +------------------ 1 file changed, 1 insertion(+), 53 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt index 0ed90bdf..13fa6123 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/login/LoginInfo.kt @@ -130,65 +130,13 @@ object LoginInfo { registerName = R.string.login_type_vulcan, registerLogo = R.drawable.login_logo_vulcan, loginModes = listOf( - Mode( - loginMode = LOGIN_MODE_VULCAN_API, - name = R.string.login_mode_vulcan_api, - icon = R.drawable.login_mode_vulcan_api, - hintText = R.string.login_mode_vulcan_api_hint, - guideText = R.string.login_mode_vulcan_api_guide, - isRecommended = true, - credentials = listOf( - FormField( - keyName = "deviceToken", - name = R.string.login_hint_token, - icon = CommunityMaterial.Icon.cmd_code_braces, - emptyText = R.string.login_error_no_token, - invalidText = R.string.login_error_incorrect_token, - errorCodes = mapOf( - ERROR_LOGIN_VULCAN_INVALID_TOKEN to R.string.login_error_incorrect_token - ), - isRequired = true, - validationRegex = "[A-Z0-9]{5,12}", - caseMode = FormField.CaseMode.UPPER_CASE - ), - FormField( - keyName = "symbol", - name = R.string.login_hint_symbol, - icon = CommunityMaterial.Icon2.cmd_school, - emptyText = R.string.login_error_no_symbol, - invalidText = R.string.login_error_incorrect_symbol, - errorCodes = mapOf( - ERROR_LOGIN_VULCAN_INVALID_SYMBOL to R.string.login_error_incorrect_symbol - ), - isRequired = true, - validationRegex = "[a-z0-9_-]+", - caseMode = FormField.CaseMode.LOWER_CASE - ), - FormField( - keyName = "devicePin", - name = R.string.login_hint_pin, - icon = CommunityMaterial.Icon2.cmd_lock, - emptyText = R.string.login_error_no_pin, - invalidText = R.string.login_error_incorrect_pin, - errorCodes = mapOf( - ERROR_LOGIN_VULCAN_INVALID_PIN to R.string.login_error_incorrect_pin - ), - isRequired = true, - validationRegex = "[0-9]+", - caseMode = FormField.CaseMode.LOWER_CASE - ) - ), - errorCodes = mapOf( - ERROR_LOGIN_VULCAN_EXPIRED_TOKEN to R.string.login_error_expired_token - ) - ), Mode( loginMode = LOGIN_MODE_VULCAN_HEBE, name = R.string.login_mode_vulcan_api, icon = R.drawable.login_mode_vulcan_hebe, hintText = R.string.login_mode_vulcan_api_hint, guideText = R.string.login_mode_vulcan_api_guide, - isTesting = true, + isRecommended = true, credentials = listOf( FormField( keyName = "deviceToken",