[API/Login] Make user action handling more universal.

This commit is contained in:
Kuba Szczodrzyński 2022-10-15 21:24:30 +02:00
parent 7ded400a30
commit 93ccdbdeb7
No known key found for this signature in database
GPG Key ID: 70CB8A85BA1633CB
23 changed files with 206 additions and 174 deletions

View File

@ -34,6 +34,7 @@ import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
import pl.droidsonroids.gif.GifDrawable import pl.droidsonroids.gif.GifDrawable
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUIRES_USER_ACTION
import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.* import pl.szczodrzynski.edziennik.data.api.events.*
@ -69,6 +70,7 @@ import pl.szczodrzynski.edziennik.ui.grades.editor.GradesEditorFragment
import pl.szczodrzynski.edziennik.ui.home.HomeFragment import pl.szczodrzynski.edziennik.ui.home.HomeFragment
import pl.szczodrzynski.edziennik.ui.homework.HomeworkFragment import pl.szczodrzynski.edziennik.ui.homework.HomeworkFragment
import pl.szczodrzynski.edziennik.ui.login.LoginActivity import pl.szczodrzynski.edziennik.ui.login.LoginActivity
import pl.szczodrzynski.edziennik.ui.login.LoginProgressFragment
import pl.szczodrzynski.edziennik.ui.messages.compose.MessagesComposeFragment import pl.szczodrzynski.edziennik.ui.messages.compose.MessagesComposeFragment
import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment
import pl.szczodrzynski.edziennik.ui.messages.single.MessageFragment import pl.szczodrzynski.edziennik.ui.messages.single.MessageFragment
@ -83,6 +85,7 @@ import pl.szczodrzynski.edziennik.utils.*
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.utils.Utils.dpToPx import pl.szczodrzynski.edziennik.utils.Utils.dpToPx
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
import pl.szczodrzynski.edziennik.utils.managers.UserActionManager
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.NavTarget import pl.szczodrzynski.edziennik.utils.models.NavTarget
import pl.szczodrzynski.navlib.* import pl.szczodrzynski.navlib.*
@ -853,7 +856,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
fun onUserActionRequiredEvent(event: UserActionRequiredEvent) { fun onUserActionRequiredEvent(event: UserActionRequiredEvent) {
app.userActionManager.execute(this, event.profileId, event.type, event.params) app.userActionManager.execute(this, event, UserActionManager.UserActionCallback())
} }
private fun fragmentToSyncName(currentFragment: Int): Int { private fun fragmentToSyncName(currentFragment: Int): Int {
@ -911,12 +914,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
false false
} }
"userActionRequired" -> { "userActionRequired" -> {
app.userActionManager.execute( val event = UserActionRequiredEvent(
this, profileId = extras.getInt("profileId"),
extras.getInt("profileId"), type = extras.getEnum<UserActionRequiredEvent.Type>("type") ?: return,
extras.getInt("type"), params = extras.getBundle("params") ?: return,
extras.getBundle("params"), errorText = 0,
) )
app.userActionManager.execute(this, event, UserActionManager.UserActionCallback())
true true
} }
"createManualEvent" -> { "createManualEvent" -> {

View File

@ -84,19 +84,21 @@ class ApiService : Service() {
runTask() runTask()
} }
override fun onRequiresUserAction(event: UserActionRequiredEvent) {
app.userActionManager.sendToUser(event)
taskRunning?.cancel()
clearTask()
runTask()
}
override fun onError(apiError: ApiError) { override fun onError(apiError: ApiError) {
lastEventTime = System.currentTimeMillis() lastEventTime = System.currentTimeMillis()
d(TAG, "Task $taskRunningId threw an error - $apiError") d(TAG, "Task $taskRunningId threw an error - $apiError")
apiError.profileId = taskProfileId apiError.profileId = taskProfileId
if (app.userActionManager.requiresUserAction(apiError)) { EventBus.getDefault().postSticky(ApiTaskErrorEvent(apiError))
app.userActionManager.sendToUser(apiError) errorList.add(apiError)
} apiError.throwable?.printStackTrace()
else {
EventBus.getDefault().postSticky(ApiTaskErrorEvent(apiError))
errorList.add(apiError)
apiError.throwable?.printStackTrace()
}
if (apiError.isCritical) { if (apiError.isCritical) {
taskRunning?.cancel() taskRunning?.cancel()

View File

@ -59,6 +59,9 @@ const val LIBRUS_SANDBOX_URL = "https://sandbox.librus.pl/index.php?action="
const val LIBRUS_SYNERGIA_HOMEWORK_ATTACHMENT_URL = "https://synergia.librus.pl/homework/downloadFile" const val LIBRUS_SYNERGIA_HOMEWORK_ATTACHMENT_URL = "https://synergia.librus.pl/homework/downloadFile"
const val LIBRUS_SYNERGIA_MESSAGES_ATTACHMENT_URL = "https://synergia.librus.pl/wiadomosci/pobierz_zalacznik" const val LIBRUS_SYNERGIA_MESSAGES_ATTACHMENT_URL = "https://synergia.librus.pl/wiadomosci/pobierz_zalacznik"
const val LIBRUS_PORTAL_RECAPTCHA_KEY = "6Lf48moUAAAAAB9ClhdvHr46gRWR"
const val LIBRUS_PORTAL_RECAPTCHA_REFERER = "https://portal.librus.pl/rodzina/login"
val MOBIDZIENNIK_USER_AGENT = SYSTEM_USER_AGENT val MOBIDZIENNIK_USER_AGENT = SYSTEM_USER_AGENT

View File

@ -58,11 +58,7 @@ const val ERROR_INVALID_LOGIN_MODE = 110
const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111 const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111
const val ERROR_NOT_IMPLEMENTED = 112 const val ERROR_NOT_IMPLEMENTED = 112
const val ERROR_FILE_DOWNLOAD = 113 const val ERROR_FILE_DOWNLOAD = 113
const val ERROR_REQUIRES_USER_ACTION = 114
const val ERROR_NO_STUDENTS_IN_ACCOUNT = 115
const val ERROR_CAPTCHA_NEEDED = 3000
const val ERROR_CAPTCHA_LIBRUS_PORTAL = 3001
const val ERROR_API_PDO_ERROR = 5000 const val ERROR_API_PDO_ERROR = 5000
const val ERROR_API_INVALID_CLIENT = 5001 const val ERROR_API_INVALID_CLIENT = 5001
@ -204,7 +200,6 @@ const val ERROR_PODLASIE_API_NO_TOKEN = 630
const val ERROR_PODLASIE_API_OTHER = 631 const val ERROR_PODLASIE_API_OTHER = 631
const val ERROR_PODLASIE_API_DATA_MISSING = 632 const val ERROR_PODLASIE_API_DATA_MISSING = 632
const val ERROR_USOS_OAUTH_LOGIN_REQUEST = 701
const val ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN = 702 const val ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN = 702
const val ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE = 703 const val ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE = 703
const val ERROR_USOS_NO_STUDENT_PROGRAMMES = 704 const val ERROR_USOS_NO_STUDENT_PROGRAMMES = 704

View File

@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.Librus
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.*
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLogin import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLogin
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
@ -162,6 +163,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback { private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
return object : EdziennikCallback { return object : EdziennikCallback {
override fun onCompleted() { callback.onCompleted() } override fun onCompleted() { callback.onCompleted() }
override fun onRequiresUserAction(event: UserActionRequiredEvent) { callback.onRequiresUserAction(event) }
override fun onProgress(step: Float) { callback.onProgress(step) } override fun onProgress(step: Float) { callback.onProgress(step) }
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) } override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
override fun onError(apiError: ApiError) { override fun onError(apiError: ApiError) {

View File

@ -10,6 +10,7 @@ import im.wangchao.mhttp.callback.TextCallbackHandler
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
@ -148,12 +149,23 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
val error = if (response.code() == 200) null else val error = if (response.code() == 200) null else
json.getJsonArray("errors")?.getString(0) json.getJsonArray("errors")?.getString(0)
?: json.getJsonObject("errors")?.entrySet()?.firstOrNull()?.value?.asString ?: json.getJsonObject("errors")?.entrySet()?.firstOrNull()?.value?.asString
if (error?.contains("robotem") == true || json.getBoolean("captchaRequired") == true) {
data.requireUserAction(
type = UserActionRequiredEvent.Type.RECAPTCHA,
params = Bundle(
"siteKey" to LIBRUS_PORTAL_RECAPTCHA_KEY,
"referer" to LIBRUS_PORTAL_RECAPTCHA_REFERER,
),
errorText = R.string.notification_user_action_required_captcha_librus,
)
return
}
error?.let { code -> error?.let { code ->
when { when {
code.contains("Sesja logowania wygasła") -> ERROR_LOGIN_LIBRUS_PORTAL_CSRF_EXPIRED code.contains("Sesja logowania wygasła") -> ERROR_LOGIN_LIBRUS_PORTAL_CSRF_EXPIRED
code.contains("Upewnij się, że nie") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN code.contains("Upewnij się, że nie") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN
// this doesn't work anyway: `errors` is an object with `g-recaptcha-response` set
code.contains("robotem") -> ERROR_CAPTCHA_LIBRUS_PORTAL
code.contains("Podany adres e-mail jest nieprawidłowy.") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN code.contains("Podany adres e-mail jest nieprawidłowy.") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN
else -> ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR else -> ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR
}.let { errorCode -> }.let { errorCode ->
@ -163,12 +175,6 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
return return
} }
} }
if (json.getBoolean("captchaRequired") == true) {
data.error(ApiError(TAG, ERROR_CAPTCHA_LIBRUS_PORTAL)
.withResponse(response)
.withApiResponse(json))
return
}
authorize(json.getString("redirect", LIBRUS_AUTHORIZE_URL)) authorize(json.getString("redirect", LIBRUS_AUTHORIZE_URL))
} }

View File

@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.Mobidzien
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web.* import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web.*
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.firstlogin.MobidziennikFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.firstlogin.MobidziennikFirstLogin
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLogin import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLogin
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
@ -142,6 +143,7 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback { private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
return object : EdziennikCallback { return object : EdziennikCallback {
override fun onCompleted() { callback.onCompleted() } override fun onCompleted() { callback.onCompleted() }
override fun onRequiresUserAction(event: UserActionRequiredEvent) { callback.onRequiresUserAction(event) }
override fun onProgress(step: Float) { callback.onProgress(step) } override fun onProgress(step: Float) { callback.onProgress(step) }
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) } override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
override fun onError(apiError: ApiError) { override fun onError(apiError: ApiError) {

View File

@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.PodlasieData
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.firstlogin.PodlasieFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.firstlogin.PodlasieFirstLogin
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLogin import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLogin
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
@ -142,6 +143,10 @@ class Podlasie(val app: App, val profile: Profile?, val loginStore: LoginStore,
callback.onCompleted() callback.onCompleted()
} }
override fun onRequiresUserAction(event: UserActionRequiredEvent) {
callback.onRequiresUserAction(event)
}
override fun onProgress(step: Float) { override fun onProgress(step: Float) {
callback.onProgress(step) callback.onProgress(step)
} }

View File

@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.CODE_INTERNAL_LIBRUS_ACCOUNT_410
import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.TemplateData import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.TemplateData
import pl.szczodrzynski.edziennik.data.api.edziennik.template.firstlogin.TemplateFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.template.firstlogin.TemplateFirstLogin
import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLogin import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLogin
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
@ -108,6 +109,10 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore,
callback.onCompleted() callback.onCompleted()
} }
override fun onRequiresUserAction(event: UserActionRequiredEvent) {
callback.onRequiresUserAction(event)
}
override fun onProgress(step: Float) { override fun onProgress(step: Float) {
callback.onProgress(step) callback.onProgress(step)
} }

View File

@ -8,6 +8,7 @@ import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin.UsosFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin.UsosFirstLogin
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLogin import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLogin
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
@ -88,6 +89,10 @@ class Usos(
callback.onCompleted() callback.onCompleted()
} }
override fun onRequiresUserAction(event: UserActionRequiredEvent) {
callback.onRequiresUserAction(event)
}
override fun onProgress(step: Float) { override fun onProgress(step: Float) {
callback.onProgress(step) callback.onProgress(step)
} }

View File

@ -4,9 +4,11 @@
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.ext.Bundle import pl.szczodrzynski.edziennik.ext.Bundle
import pl.szczodrzynski.edziennik.ext.fromQueryString import pl.szczodrzynski.edziennik.ext.fromQueryString
@ -53,13 +55,16 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) {
"interactivity" to "confirm_user", "interactivity" to "confirm_user",
"oauth_token" to (data.oauthTokenKey ?: ""), "oauth_token" to (data.oauthTokenKey ?: ""),
) )
val params = Bundle( data.requireUserAction(
"authorizeUrl" to "$authUrl?${authParams.toQueryString()}", type = UserActionRequiredEvent.Type.OAUTH,
"redirectUrl" to USOS_API_OAUTH_REDIRECT_URL, params = Bundle(
"responseStoreKey" to "oauthLoginResponse", "authorizeUrl" to "$authUrl?${authParams.toQueryString()}",
"extras" to data.loginStore.data.toBundle(), "redirectUrl" to USOS_API_OAUTH_REDIRECT_URL,
"responseStoreKey" to "oauthLoginResponse",
"extras" to data.loginStore.data.toBundle(),
),
errorText = R.string.notification_user_action_required_oauth_usos,
) )
data.error(ApiError(TAG, ERROR_USOS_OAUTH_LOGIN_REQUEST).withParams(params))
} }
} }
@ -93,6 +98,7 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) {
data.oauthTokenKey = accessData["oauth_token"] data.oauthTokenKey = accessData["oauth_token"]
data.oauthTokenSecret = accessData["oauth_token_secret"] data.oauthTokenSecret = accessData["oauth_token_secret"]
data.oauthTokenIsUser = data.oauthTokenKey != null && data.oauthTokenSecret != null data.oauthTokenIsUser = data.oauthTokenKey != null && data.oauthTokenSecret != null
data.loginStore.removeLoginData("oauthLoginResponse")
if (!data.oauthTokenIsUser) if (!data.oauthTokenIsUser)
data.error(ApiError(TAG, ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE) data.error(ApiError(TAG, ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE)

View File

@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLogin
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
@ -179,6 +180,7 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback { private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
return object : EdziennikCallback { return object : EdziennikCallback {
override fun onCompleted() { callback.onCompleted() } override fun onCompleted() { callback.onCompleted() }
override fun onRequiresUserAction(event: UserActionRequiredEvent) { callback.onRequiresUserAction(event) }
override fun onProgress(step: Float) { callback.onProgress(step) } override fun onProgress(step: Float) { callback.onProgress(step) }
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) } override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
override fun onError(apiError: ApiError) { override fun onError(apiError: ApiError) {

View File

@ -6,12 +6,14 @@ package pl.szczodrzynski.edziennik.data.api.events
import android.os.Bundle import android.os.Bundle
data class UserActionRequiredEvent(val profileId: Int, val type: Int, val params: Bundle?) { data class UserActionRequiredEvent(
companion object { val profileId: Int?,
const val LOGIN_DATA_MOBIDZIENNIK = 101 val type: Type,
const val LOGIN_DATA_LIBRUS = 102 val params: Bundle,
const val LOGIN_DATA_VULCAN = 104 val errorText: Int,
const val CAPTCHA_LIBRUS = 202 ) {
const val OAUTH_USOS = 701 enum class Type {
RECAPTCHA,
OAUTH,
} }
} }

View File

@ -4,6 +4,7 @@
package pl.szczodrzynski.edziennik.data.api.interfaces package pl.szczodrzynski.edziennik.data.api.interfaces
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.models.Feature import pl.szczodrzynski.edziennik.data.api.models.Feature
import pl.szczodrzynski.edziennik.data.api.models.LoginMethod import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
@ -14,4 +15,5 @@ import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
*/ */
interface EdziennikCallback : EndpointCallback { interface EdziennikCallback : EndpointCallback {
fun onCompleted() fun onCompleted()
fun onRequiresUserAction(event: UserActionRequiredEvent)
} }

View File

@ -1,5 +1,6 @@
package pl.szczodrzynski.edziennik.data.api.models package pl.szczodrzynski.edziennik.data.api.models
import android.os.Bundle
import android.util.LongSparseArray import android.util.LongSparseArray
import android.util.SparseArray import android.util.SparseArray
import androidx.core.util.set import androidx.core.util.set
@ -12,7 +13,8 @@ import pl.szczodrzynski.edziennik.BuildConfig
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE
import pl.szczodrzynski.edziennik.data.api.Regexes.MESSAGE_META import pl.szczodrzynski.edziennik.data.api.Regexes.MESSAGE_META
import pl.szczodrzynski.edziennik.data.api.interfaces.EndpointCallback import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.* import pl.szczodrzynski.edziennik.data.db.entity.*
import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ext.*
@ -37,7 +39,7 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
/** /**
* A callback passed to all [Feature]s and [LoginMethod]s * A callback passed to all [Feature]s and [LoginMethod]s
*/ */
lateinit var callback: EndpointCallback lateinit var callback: EdziennikCallback
/** /**
* A list of [LoginMethod]s *already fulfilled* during this sync. * A list of [LoginMethod]s *already fulfilled* during this sync.
@ -374,6 +376,15 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
callback.onError(apiError) callback.onError(apiError)
} }
fun requireUserAction(type: UserActionRequiredEvent.Type, params: Bundle, errorText: Int) {
callback.onRequiresUserAction(UserActionRequiredEvent(
profileId = profile?.id,
type = type,
params = params,
errorText = errorText,
))
}
fun progress(step: Float) { fun progress(step: Float) {
callback.onProgress(step) callback.onProgress(step)
} }

View File

@ -22,6 +22,15 @@ fun Bundle?.getFloat(key: String, defaultValue: Float): Float {
fun Bundle?.getString(key: String, defaultValue: String): String { fun Bundle?.getString(key: String, defaultValue: String): String {
return this?.getString(key, defaultValue) ?: defaultValue return this?.getString(key, defaultValue) ?: defaultValue
} }
inline fun <reified E : Enum<E>> Bundle?.getEnum(key: String): E? {
return this?.getString(key)?.let {
try {
enumValueOf<E>(it)
} catch (e: Exception) {
null
}
}
}
fun Bundle?.getIntOrNull(key: String): Int? { fun Bundle?.getIntOrNull(key: String): Int? {
return this?.get(key) as? Int return this?.get(key) as? Int
@ -48,6 +57,7 @@ fun Bundle(vararg properties: Pair<String, Any?>): Bundle {
is Bundle -> putBundle(property.first, property.second as Bundle) is Bundle -> putBundle(property.first, property.second as Bundle)
is Parcelable -> putParcelable(property.first, property.second as Parcelable) is Parcelable -> putParcelable(property.first, property.second as Parcelable)
is Array<*> -> putParcelableArray(property.first, property.second as Array<out Parcelable>) is Array<*> -> putParcelableArray(property.first, property.second as Array<out Parcelable>)
is Enum<*> -> putString(property.first, (property.second as Enum<*>).name)
} }
} }
} }

View File

@ -13,14 +13,16 @@ import pl.szczodrzynski.edziennik.databinding.RecaptchaViewBinding
import pl.szczodrzynski.edziennik.ext.onClick import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ui.dialogs.base.BindingDialog import pl.szczodrzynski.edziennik.ui.dialogs.base.BindingDialog
class LibrusCaptchaDialog( class RecaptchaPromptDialog(
activity: AppCompatActivity, activity: AppCompatActivity,
private val siteKey: String,
private val referer: String,
private val onSuccess: (recaptchaCode: String) -> Unit, private val onSuccess: (recaptchaCode: String) -> Unit,
private val onFailure: (() -> Unit)?, private val onCancel: (() -> Unit)?,
onShowListener: ((tag: String) -> Unit)? = null, onShowListener: ((tag: String) -> Unit)? = null,
onDismissListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null,
) : BindingDialog<RecaptchaViewBinding>(activity, onShowListener, onDismissListener) { ) : BindingDialog<RecaptchaViewBinding>(activity, onShowListener, onDismissListener) {
override val TAG = "LibrusCaptchaDialog" override val TAG = "RecaptchaPromptDialog"
override fun getTitleRes(): Int? = null override fun getTitleRes(): Int? = null
override fun inflate(layoutInflater: LayoutInflater) = override fun inflate(layoutInflater: LayoutInflater) =
@ -46,8 +48,8 @@ class LibrusCaptchaDialog(
b.progress.visibility = View.VISIBLE b.progress.visibility = View.VISIBLE
RecaptchaDialog( RecaptchaDialog(
activity, activity,
siteKey = "6Lf48moUAAAAAB9ClhdvHr46gRWR-CN31CXQPG2U", siteKey = siteKey,
referer = "https://portal.librus.pl/rodzina/login", referer = referer,
onSuccess = { recaptchaCode -> onSuccess = { recaptchaCode ->
b.checkbox.background = checkboxBackground b.checkbox.background = checkboxBackground
b.checkbox.foreground = checkboxForeground b.checkbox.foreground = checkboxForeground
@ -67,6 +69,6 @@ class LibrusCaptchaDialog(
override fun onDismiss() { override fun onDismiss() {
if (!success) if (!success)
onFailure?.invoke() onCancel?.invoke()
} }
} }

View File

@ -27,7 +27,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.databinding.CardHomeDebugBinding import pl.szczodrzynski.edziennik.databinding.CardHomeDebugBinding
import pl.szczodrzynski.edziennik.ext.dp import pl.szczodrzynski.edziennik.ext.dp
import pl.szczodrzynski.edziennik.ext.onClick import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ui.captcha.LibrusCaptchaDialog import pl.szczodrzynski.edziennik.ui.captcha.RecaptchaPromptDialog
import pl.szczodrzynski.edziennik.ui.home.HomeCard import pl.szczodrzynski.edziennik.ui.home.HomeCard
import pl.szczodrzynski.edziennik.ui.home.HomeCardAdapter import pl.szczodrzynski.edziennik.ui.home.HomeCardAdapter
import pl.szczodrzynski.edziennik.ui.home.HomeFragment import pl.szczodrzynski.edziennik.ui.home.HomeFragment
@ -85,11 +85,6 @@ class HomeDebugCard(
app.startActivity(Chucker.getLaunchIntent(activity, 1)); app.startActivity(Chucker.getLaunchIntent(activity, 1));
} }
b.librusCaptchaButton.onClick {
//app.startActivity(Intent(activity, LoginLibrusCaptchaActivity::class.java))
LibrusCaptchaDialog(activity, onSuccess = {}, onFailure = {}).show()
}
b.getLogs.onClick { b.getLogs.onClick {
val logs = HyperLog.getDeviceLogsInFile(activity, true) val logs = HyperLog.getDeviceLogsInFile(activity, true)
val intent = Intent(Intent.ACTION_SEND) val intent = Intent(Intent.ACTION_SEND)

View File

@ -65,7 +65,6 @@ object LoginInfo {
errorCodes = mapOf( errorCodes = mapOf(
ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED to R.string.login_error_account_not_activated, ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED to R.string.login_error_account_not_activated,
ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN to R.string.login_error_incorrect_login_or_password, ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN to R.string.login_error_incorrect_login_or_password,
ERROR_CAPTCHA_LIBRUS_PORTAL to R.string.error_3001_reason
) )
), ),
/*Mode( /*Mode(

View File

@ -19,7 +19,7 @@ import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.ERROR_CAPTCHA_NEEDED import pl.szczodrzynski.edziennik.data.api.ERROR_REQUIRES_USER_ACTION
import pl.szczodrzynski.edziennik.data.api.LOGIN_NO_ARGUMENTS import pl.szczodrzynski.edziennik.data.api.LOGIN_NO_ARGUMENTS
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent
@ -29,6 +29,7 @@ import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.databinding.LoginProgressFragmentBinding import pl.szczodrzynski.edziennik.databinding.LoginProgressFragmentBinding
import pl.szczodrzynski.edziennik.ext.joinNotNullStrings import pl.szczodrzynski.edziennik.ext.joinNotNullStrings
import pl.szczodrzynski.edziennik.utils.managers.UserActionManager
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.math.max import kotlin.math.max
@ -137,13 +138,21 @@ class LoginProgressFragment : Fragment(), CoroutineScope {
return return
} }
app.userActionManager.execute(activity, event.profileId, event.type, event.params, onSuccess = { params -> val callback = UserActionManager.UserActionCallback(
args.putAll(params) onSuccess = { data ->
doFirstLogin(args) args.putAll(data)
}, onFailure = { doFirstLogin(args)
activity.error(ApiError(TAG, ERROR_CAPTCHA_NEEDED)) },
nav.navigateUp() onFailure = {
}) activity.error(ApiError(TAG, ERROR_REQUIRES_USER_ACTION))
nav.navigateUp()
},
onCancel = {
nav.navigateUp()
},
)
app.userActionManager.execute(activity, event, callback)
} }
override fun onStart() { override fun onStart() {

View File

@ -16,13 +16,10 @@ import org.greenrobot.eventbus.ThreadMode
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.ERROR_CAPTCHA_LIBRUS_PORTAL
import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_OAUTH_LOGIN_REQUEST
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.ui.captcha.LibrusCaptchaDialog import pl.szczodrzynski.edziennik.ui.captcha.RecaptchaPromptDialog
import pl.szczodrzynski.edziennik.ui.login.oauth.OAuthLoginActivity import pl.szczodrzynski.edziennik.ui.login.oauth.OAuthLoginActivity
import pl.szczodrzynski.edziennik.ui.login.oauth.OAuthLoginResult import pl.szczodrzynski.edziennik.ui.login.oauth.OAuthLoginResult
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
@ -32,43 +29,31 @@ class UserActionManager(val app: App) {
private const val TAG = "UserActionManager" private const val TAG = "UserActionManager"
} }
fun requiresUserAction(apiError: ApiError) = when (apiError.errorCode) { fun sendToUser(event: UserActionRequiredEvent) {
ERROR_CAPTCHA_LIBRUS_PORTAL -> true
ERROR_USOS_OAUTH_LOGIN_REQUEST -> true
else -> false
}
fun sendToUser(apiError: ApiError) {
val type = when (apiError.errorCode) {
ERROR_CAPTCHA_LIBRUS_PORTAL -> UserActionRequiredEvent.CAPTCHA_LIBRUS
ERROR_USOS_OAUTH_LOGIN_REQUEST -> UserActionRequiredEvent.OAUTH_USOS
else -> 0
}
if (EventBus.getDefault().hasSubscriberForEvent(UserActionRequiredEvent::class.java)) { if (EventBus.getDefault().hasSubscriberForEvent(UserActionRequiredEvent::class.java)) {
EventBus.getDefault().post(UserActionRequiredEvent(apiError.profileId ?: -1, type, apiError.params)) EventBus.getDefault().post(event)
return return
} }
val manager = app.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val manager = app.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val text = app.getString(event.errorText, event.profileId)
val text = app.getString(when (type) {
UserActionRequiredEvent.CAPTCHA_LIBRUS -> R.string.notification_user_action_required_captcha_librus
UserActionRequiredEvent.OAUTH_USOS -> R.string.notification_user_action_required_oauth_usos
else -> R.string.notification_user_action_required_text
}, apiError.profileId)
val intent = Intent( val intent = Intent(
app, app,
MainActivity::class.java, MainActivity::class.java,
"action" to "userActionRequired", "action" to "userActionRequired",
"profileId" to (apiError.profileId ?: -1), "profileId" to event.profileId,
"type" to type, "type" to event.type,
"params" to apiError.params, "params" to event.params,
)
val pendingIntent = PendingIntent.getActivity(
app,
System.currentTimeMillis().toInt(),
intent,
PendingIntent.FLAG_ONE_SHOT or pendingIntentFlag(),
) )
val pendingIntent = PendingIntent.getActivity(app, System.currentTimeMillis().toInt(), intent, PendingIntent.FLAG_ONE_SHOT or pendingIntentFlag())
val notification = NotificationCompat.Builder(app, app.notificationChannelsManager.userAttention.key) val notification =
NotificationCompat.Builder(app, app.notificationChannelsManager.userAttention.key)
.setContentTitle(app.getString(R.string.notification_user_action_required_title)) .setContentTitle(app.getString(R.string.notification_user_action_required_title))
.setContentText(text) .setContentText(text)
.setSmallIcon(R.drawable.ic_error_outline) .setSmallIcon(R.drawable.ic_error_outline)
@ -84,70 +69,56 @@ class UserActionManager(val app: App) {
manager.notify(System.currentTimeMillis().toInt(), notification) manager.notify(System.currentTimeMillis().toInt(), notification)
} }
class UserActionCallback(
val onSuccess: ((data: Bundle) -> Unit)? = null,
val onFailure: (() -> Unit)? = null,
val onCancel: (() -> Unit)? = null,
)
fun execute( fun execute(
activity: AppCompatActivity, activity: AppCompatActivity,
profileId: Int?, event: UserActionRequiredEvent,
type: Int, callback: UserActionCallback,
params: Bundle? = null,
onSuccess: ((params: Bundle) -> Unit)? = null,
onFailure: (() -> Unit)? = null
) { ) {
d(TAG, "Running user action ($type) with params: ${params?.toJsonObject()}") d(TAG, "Running user action (${event.type}) with params: ${event.params}")
val isSuccessful = when (type) { val isSuccessful = when (event.type) {
UserActionRequiredEvent.CAPTCHA_LIBRUS -> executeLibrus(activity, profileId, params, onSuccess, onFailure) UserActionRequiredEvent.Type.RECAPTCHA -> executeRecaptcha(activity, event, callback)
UserActionRequiredEvent.OAUTH_USOS -> executeOauth(activity, profileId, params, onSuccess, onFailure) UserActionRequiredEvent.Type.OAUTH -> executeOauth(activity, event, callback)
else -> false
}
if (!isSuccessful) {
onFailure?.invoke()
} }
if (!isSuccessful)
callback.onFailure?.invoke()
} }
private fun executeLibrus( private fun executeRecaptcha(
activity: AppCompatActivity, activity: AppCompatActivity,
profileId: Int?, event: UserActionRequiredEvent,
params: Bundle?, callback: UserActionCallback,
onSuccess: ((params: Bundle) -> Unit)?,
onFailure: (() -> Unit)?,
): Boolean { ): Boolean {
if (profileId == null) val siteKey = event.params.getString("siteKey") ?: return false
return false val referer = event.params.getString("referer") ?: return false
val extras = params?.getBundle("extras") RecaptchaPromptDialog(
// show captcha dialog
// use passed onSuccess listener, else sync profile
LibrusCaptchaDialog(
activity = activity, activity = activity,
siteKey = siteKey,
referer = referer,
onSuccess = { code -> onSuccess = { code ->
val args = Bundle( finishAction(activity, event, callback, Bundle(
"recaptchaCode" to code, "recaptchaCode" to code,
"recaptchaTime" to System.currentTimeMillis(), "recaptchaTime" to System.currentTimeMillis(),
) ))
if (extras != null)
args.putAll(extras)
if (onSuccess != null)
onSuccess(args)
else
EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity)
}, },
onFailure = onFailure, onCancel = callback.onCancel,
).show() ).show()
return true return true
} }
private fun executeOauth( private fun executeOauth(
activity: AppCompatActivity, activity: AppCompatActivity,
profileId: Int?, event: UserActionRequiredEvent,
params: Bundle?, callback: UserActionCallback,
onSuccess: ((params: Bundle) -> Unit)?,
onFailure: (() -> Unit)?,
): Boolean { ): Boolean {
if (profileId == null || params == null) val storeKey = event.params.getString("responseStoreKey") ?: return false
return false event.params.getString("authorizeUrl") ?: return false
val extras = params.getBundle("extras") event.params.getString("redirectUrl") ?: return false
val storeKey = params.getString("responseStoreKey") ?: return false
params.getString("authorizeUrl") ?: return false
params.getString("redirectUrl") ?: return false
var listener: Any? = null var listener: Any? = null
listener = object { listener = object {
@ -155,26 +126,41 @@ class UserActionManager(val app: App) {
fun onOAuthLoginResult(result: OAuthLoginResult) { fun onOAuthLoginResult(result: OAuthLoginResult) {
EventBus.getDefault().unregister(listener) EventBus.getDefault().unregister(listener)
when { when {
result.isError -> onFailure?.invoke() result.isError -> callback.onFailure?.invoke()
result.responseUrl != null -> { result.responseUrl != null -> {
val args = Bundle( finishAction(activity, event, callback, Bundle(
storeKey to result.responseUrl, storeKey to result.responseUrl,
) ))
if (extras != null)
args.putAll(extras)
if (onSuccess != null)
onSuccess(args)
else
EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity)
} }
else -> callback.onCancel?.invoke()
} }
} }
} }
EventBus.getDefault().register(listener) EventBus.getDefault().register(listener)
val intent = Intent(activity, OAuthLoginActivity::class.java).putExtras(params) val intent = Intent(activity, OAuthLoginActivity::class.java).putExtras(event.params)
activity.startActivity(intent) activity.startActivity(intent)
return true return true
} }
private fun finishAction(
activity: AppCompatActivity,
event: UserActionRequiredEvent,
callback: UserActionCallback,
data: Bundle,
) {
val extras = event.params.getBundle("extras")
if (extras != null)
data.putAll(extras)
if (callback.onSuccess != null)
callback.onSuccess.invoke(data)
else if (event.profileId != null)
EdziennikTask.syncProfile(
profileId = event.profileId,
arguments = data.toJsonObject(),
).enqueue(activity)
else
callback.onFailure?.invoke()
}
} }

View File

@ -25,13 +25,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Save Debug Logs" /> android:text="Save Debug Logs" />
<com.google.android.material.button.MaterialButton
android:id="@+id/librusCaptchaButton"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="LIBRUS® Captcha" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/refreshWidget" android:id="@+id/refreshWidget"
style="@style/Widget.MaterialComponents.Button" style="@style/Widget.MaterialComponents.Button"

View File

@ -31,11 +31,6 @@
<string name="error_112" translatable="false">ERROR_NOT_IMPLEMENTED</string> <string name="error_112" translatable="false">ERROR_NOT_IMPLEMENTED</string>
<string name="error_113" translatable="false">ERROR_FILE_DOWNLOAD</string> <string name="error_113" translatable="false">ERROR_FILE_DOWNLOAD</string>
<string name="error_115" translatable="false">ERROR_NO_STUDENTS_IN_ACCOUNT</string>
<string name="error_3000" translatable="false">ERROR_CAPTCHA_NEEDED</string>
<string name="error_3001" translatable="false">ERROR_CAPTCHA_LIBRUS_PORTAL</string>
<string name="error_5000" translatable="false">ERROR_API_PDO_ERROR</string> <string name="error_5000" translatable="false">ERROR_API_PDO_ERROR</string>
<string name="error_5001" translatable="false">ERROR_API_INVALID_CLIENT</string> <string name="error_5001" translatable="false">ERROR_API_INVALID_CLIENT</string>
<string name="error_5002" translatable="false">ERROR_API_INVALID_ARGUMENT</string> <string name="error_5002" translatable="false">ERROR_API_INVALID_ARGUMENT</string>
@ -174,8 +169,6 @@
<string name="error_631" translatable="false">ERROR_PODLASIE_API_OTHER</string> <string name="error_631" translatable="false">ERROR_PODLASIE_API_OTHER</string>
<string name="error_632" translatable="false">ERROR_PODLASIE_API_DATA_MISSING</string> <string name="error_632" translatable="false">ERROR_PODLASIE_API_DATA_MISSING</string>
<string name="error_701" translatable="false">ERROR_USOS_OAUTH_LOGIN_REQUEST</string>
<string name="error_801" translatable="false">ERROR_TEMPLATE_WEB_OTHER</string> <string name="error_801" translatable="false">ERROR_TEMPLATE_WEB_OTHER</string>
<string name="error_900" translatable="false">EXCEPTION_API_TASK</string> <string name="error_900" translatable="false">EXCEPTION_API_TASK</string>
@ -223,11 +216,6 @@
<string name="error_112_reason">Nie zaimplementowano</string> <string name="error_112_reason">Nie zaimplementowano</string>
<string name="error_113_reason">Wystąpił błąd podczas pobierania pliku. Dziennik może być przeciążony lub mieć przerwę techniczną.</string> <string name="error_113_reason">Wystąpił błąd podczas pobierania pliku. Dziennik może być przeciążony lub mieć przerwę techniczną.</string>
<string name="error_115_reason">Brak uczniów przypisanych do konta</string>
<string name="error_3000_reason">Wymagane rozwiązanie zadania Captcha</string>
<string name="error_3001_reason">LIBRUS®: wymagane rozwiązanie zadania Captcha</string>
<string name="error_5000_reason">ERROR_API_PDO_ERROR</string> <string name="error_5000_reason">ERROR_API_PDO_ERROR</string>
<string name="error_5001_reason">Nieprawidłowy ID klienta API</string> <string name="error_5001_reason">Nieprawidłowy ID klienta API</string>
<string name="error_5002_reason">API: nieprawidłowy argument</string> <string name="error_5002_reason">API: nieprawidłowy argument</string>
@ -366,8 +354,6 @@
<string name="error_631_reason">ERROR_PODLASIE_API_OTHER</string> <string name="error_631_reason">ERROR_PODLASIE_API_OTHER</string>
<string name="error_632_reason">Brak danych. Zgłoś błąd programiście.</string> <string name="error_632_reason">Brak danych. Zgłoś błąd programiście.</string>
<string name="error_701_reason">Wymagane logowanie w przeglądarce</string>
<string name="error_801_reason">ERROR_TEMPLATE_WEB_OTHER</string> <string name="error_801_reason">ERROR_TEMPLATE_WEB_OTHER</string>
<string name="error_900_reason">Błąd synchronizacji. Upewnij się, że masz połączenie z internetem, a następnie zgłoś błąd.</string> <string name="error_900_reason">Błąd synchronizacji. Upewnij się, że masz połączenie z internetem, a następnie zgłoś błąd.</string>