diff --git a/.idea/dictionaries/Kuba.xml b/.idea/dictionaries/Kuba.xml
index 592a5d5e..aba38775 100644
--- a/.idea/dictionaries/Kuba.xml
+++ b/.idea/dictionaries/Kuba.xml
@@ -13,6 +13,7 @@
synergia
szczodrzyński
szkolny
+ usos
\ No newline at end of file
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 227561e6..617ef5ed 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
@@ -204,6 +204,8 @@ const val ERROR_PODLASIE_API_NO_TOKEN = 630
const val ERROR_PODLASIE_API_OTHER = 631
const val ERROR_PODLASIE_API_DATA_MISSING = 632
+const val ERROR_USOS_OAUTH_LOGIN_REQUEST = 701
+
const val ERROR_TEMPLATE_WEB_OTHER = 801
const val EXCEPTION_API_TASK = 900
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 0f0c07ae..9825ea3f 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
@@ -13,6 +13,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.Mobidzie
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLoginApi
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.usos.login.UsosLoginApi
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
@@ -127,6 +128,15 @@ val podlasieLoginMethods = listOf(
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
)
+const val LOGIN_TYPE_USOS = 7
+const val LOGIN_MODE_USOS_OAUTH = 0
+const val LOGIN_METHOD_USOS_API = 100
+val usosLoginMethods = listOf(
+ LoginMethod(LOGIN_TYPE_USOS, LOGIN_METHOD_USOS_API, UsosLoginApi::class.java)
+ .withIsPossible { _, _ -> true }
+ .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
+)
+
val templateLoginMethods = listOf(
LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_WEB, TemplateLoginWeb::class.java)
.withIsPossible { _, _ -> true }
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt
new file mode 100644
index 00000000..b4a925bf
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2022-10-11.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.usos
+
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_USOS_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
+
+class DataUsos(
+ app: App,
+ profile: Profile?,
+ loginStore: LoginStore,
+) : Data(app, profile, loginStore) {
+
+ fun isApiLoginValid() = oauthTokenKey != null && oauthTokenSecret != null
+
+ override fun satisfyLoginMethods() {
+ loginMethods.clear()
+ if (isApiLoginValid()) {
+ loginMethods += LOGIN_METHOD_USOS_API
+ }
+ }
+
+ override fun generateUserCode() = "USOS:TEST"
+
+ var oauthTokenKey: String?
+ get() { mOauthTokenKey = mOauthTokenKey ?: loginStore.getLoginData("oauthTokenKey", null); return mOauthTokenKey }
+ set(value) { loginStore.putLoginData("oauthTokenKey", value); mOauthTokenKey = value }
+ private var mOauthTokenKey: String? = null
+
+ var oauthTokenSecret: String?
+ get() { mOauthTokenSecret = mOauthTokenSecret ?: loginStore.getLoginData("oauthTokenSecret", null); return mOauthTokenSecret }
+ set(value) { loginStore.putLoginData("oauthTokenSecret", value); mOauthTokenSecret = value }
+ private var mOauthTokenSecret: String? = null
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt
new file mode 100644
index 00000000..c97e3695
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2022-10-11.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.usos
+
+import com.google.gson.JsonObject
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLogin
+import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
+import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.api.prepare
+import pl.szczodrzynski.edziennik.data.api.usosLoginMethods
+import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
+import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.data.db.entity.Teacher
+import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
+import pl.szczodrzynski.edziennik.data.db.full.EventFull
+import pl.szczodrzynski.edziennik.data.db.full.MessageFull
+import pl.szczodrzynski.edziennik.utils.Utils.d
+
+class Usos(
+ val app: App,
+ val profile: Profile?,
+ val loginStore: LoginStore,
+ val callback: EdziennikCallback,
+) : EdziennikInterface {
+ companion object {
+ private const val TAG = "Usos"
+ }
+
+ val internalErrorList = mutableListOf()
+ val data: DataUsos
+
+ init {
+ data = DataUsos(app, profile, loginStore).apply {
+ callback = wrapCallback(this@Usos.callback)
+ satisfyLoginMethods()
+ }
+ }
+
+ private fun completed() {
+ data.saveData()
+ callback.onCompleted()
+ }
+
+ override fun sync(
+ featureIds: List,
+ viewId: Int?,
+ onlyEndpoints: List?,
+ arguments: JsonObject?,
+ ) {
+ data.arguments = arguments
+ data.prepare(usosLoginMethods, UsosFeatures, featureIds, viewId, onlyEndpoints)
+ d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
+ d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
+ UsosLogin(data) {
+ /*UsosData(data) {
+ completed()
+ }*/
+ }
+ }
+
+ override fun getMessage(message: MessageFull) {}
+ override fun sendMessage(recipients: List, subject: String, text: String) {}
+ override fun markAllAnnouncementsAsRead() {}
+ override fun getAnnouncement(announcement: AnnouncementFull) {}
+ override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {}
+ override fun getRecipientList() {}
+ override fun getEvent(eventFull: EventFull) {}
+
+ override fun firstLogin() {
+ /*UsosFirstLogin(data) {
+ completed()
+ }*/
+ }
+
+ override fun cancel() {
+ d(TAG, "Cancelled")
+ data.cancel()
+ }
+
+ private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
+ return object : EdziennikCallback {
+ override fun onCompleted() {
+ callback.onCompleted()
+ }
+
+ override fun onProgress(step: Float) {
+ callback.onProgress(step)
+ }
+
+ override fun onStartProgress(stringRes: Int) {
+ callback.onStartProgress(stringRes)
+ }
+
+ override fun onError(apiError: ApiError) {
+ when (apiError.errorCode) {
+ in internalErrorList -> {
+ // finish immediately if the same error occurs twice during the same sync
+ callback.onError(apiError)
+ }
+ else -> callback.onError(apiError)
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt
new file mode 100644
index 00000000..a4ee1389
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2022-10-11.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.usos
+
+import pl.szczodrzynski.edziennik.data.api.FEATURE_STUDENT_INFO
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_USOS_API
+import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_USOS
+import pl.szczodrzynski.edziennik.data.api.models.Feature
+
+const val ENDPOINT_USOS_API_USER = 7000
+
+val UsosFeatures = listOf(
+ Feature(LOGIN_TYPE_USOS, FEATURE_STUDENT_INFO, listOf(
+ ENDPOINT_USOS_API_USER to LOGIN_METHOD_USOS_API,
+ ), listOf(LOGIN_METHOD_USOS_API)),
+)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLogin.kt
new file mode 100644
index 00000000..599b8f16
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLogin.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2022-10-11.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login
+
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_USOS_API
+import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
+import pl.szczodrzynski.edziennik.utils.Utils.d
+
+class UsosLogin(val data: DataUsos, val onSuccess: () -> Unit) {
+ companion object {
+ private const val TAG = "UsosLogin"
+ }
+
+ private var cancelled = false
+
+ init {
+ nextLoginMethod(onSuccess)
+ }
+
+ private fun nextLoginMethod(onSuccess: () -> Unit) {
+ if (data.targetLoginMethodIds.isEmpty()) {
+ onSuccess()
+ return
+ }
+ if (cancelled) {
+ onSuccess()
+ return
+ }
+ useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId ->
+ data.progress(data.progressStep)
+ if (usedMethodId != -1)
+ data.loginMethods.add(usedMethodId)
+ nextLoginMethod(onSuccess)
+ }
+ }
+
+ private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) {
+ // this should never be true
+ if (data.loginMethods.contains(loginMethodId)) {
+ onSuccess(-1)
+ return
+ }
+ d(TAG, "Using login method $loginMethodId")
+ when (loginMethodId) {
+ LOGIN_METHOD_USOS_API -> {
+ data.startProgress(R.string.edziennik_progress_login_usos_api)
+ UsosLoginApi(data) { onSuccess(loginMethodId) }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt
new file mode 100644
index 00000000..bdf771c3
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2022-10-11.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login
+
+import pl.szczodrzynski.edziennik.data.api.ERROR_PROFILE_MISSING
+import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_OAUTH_LOGIN_REQUEST
+import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+
+class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) {
+ companion object {
+ private const val TAG = "UsosLoginApi"
+ }
+
+ init { run {
+ if (data.profile == null) {
+ data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
+ return@run
+ }
+
+ if (data.isApiLoginValid()) {
+ onSuccess()
+ } else {
+ data.error(ApiError(TAG, ERROR_USOS_OAUTH_LOGIN_REQUEST))
+ }
+ }}
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt
index 0448b514..be6d62d8 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt
@@ -313,7 +313,24 @@ object LoginInfo {
errorCodes = mapOf()
)
)
- )
+ ),
+ Register(
+ loginType = LOGIN_TYPE_USOS,
+ internalName = "usos",
+ registerName = R.string.login_type_usos,
+ registerLogo = R.drawable.login_logo_usos,
+ loginModes = listOf(
+ Mode(
+ loginMode = LOGIN_MODE_USOS_OAUTH,
+ name = R.string.login_mode_usos_oauth,
+ icon = R.drawable.login_logo_usos,
+ guideText = R.string.login_mode_usos_oauth_guide,
+ isPlatformSelection = true,
+ credentials = listOf(),
+ errorCodes = mapOf(),
+ ),
+ ),
+ ),
)
}
diff --git a/app/src/main/res/drawable/login_logo_usos.png b/app/src/main/res/drawable/login_logo_usos.png
new file mode 100644
index 00000000..7c376bdd
Binary files /dev/null and b/app/src/main/res/drawable/login_logo_usos.png differ
diff --git a/app/src/main/res/values/errors.xml b/app/src/main/res/values/errors.xml
index f0916a8b..4e978f7b 100644
--- a/app/src/main/res/values/errors.xml
+++ b/app/src/main/res/values/errors.xml
@@ -174,6 +174,8 @@
ERROR_PODLASIE_API_OTHER
ERROR_PODLASIE_API_DATA_MISSING
+ ERROR_USOS_OAUTH_LOGIN_REQUEST
+
ERROR_TEMPLATE_WEB_OTHER
EXCEPTION_API_TASK
@@ -364,6 +366,8 @@
ERROR_PODLASIE_API_OTHER
Brak danych. Zgłoś błąd programiście.
+ Wymagane logowanie w przeglądarce
+
ERROR_TEMPLATE_WEB_OTHER
Błąd synchronizacji. Upewnij się, że masz połączenie z internetem, a następnie zgłoś błąd.
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a8f81073..66ac0299 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1537,4 +1537,8 @@
(rodzic)
- nieznany przedmiot -
{cmd-information-outline} Oceny, których przedmiot nie został podany w dzienniku. Może to być na przykład taki, który nie jest prowadzony w tym roku szkolnym.
+ Logowanie do USOS API...
+ USOS
+ Logowanie z użyciem przeglądarki
+ TODO