forked from github/szkolny
[API/Usos] Implement first login.
This commit is contained in:
parent
2ff784066e
commit
7ded400a30
@ -157,6 +157,10 @@
|
|||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:theme="@style/Base.Theme.AppCompat" />
|
android:theme="@style/Base.Theme.AppCompat" />
|
||||||
|
<activity android:name=".ui.login.oauth.OAuthLoginActivity"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:exported="false"
|
||||||
|
android:theme="@style/AppTheme.Light" />
|
||||||
<activity android:name=".ui.base.BuildInvalidActivity" android:exported="false" />
|
<activity android:name=".ui.base.BuildInvalidActivity" android:exported="false" />
|
||||||
<activity android:name=".ui.settings.contributors.ContributorsActivity" android:exported="false" />
|
<activity android:name=".ui.settings.contributors.ContributorsActivity" android:exported="false" />
|
||||||
|
|
||||||
|
@ -205,6 +205,9 @@ 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_LOGIN_REQUEST = 701
|
||||||
|
const val ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN = 702
|
||||||
|
const val ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE = 703
|
||||||
|
const val ERROR_USOS_NO_STUDENT_PROGRAMMES = 704
|
||||||
|
|
||||||
const val ERROR_TEMPLATE_WEB_OTHER = 801
|
const val ERROR_TEMPLATE_WEB_OTHER = 801
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ class DataUsos(
|
|||||||
loginStore: LoginStore,
|
loginStore: LoginStore,
|
||||||
) : Data(app, profile, loginStore) {
|
) : Data(app, profile, loginStore) {
|
||||||
|
|
||||||
fun isApiLoginValid() = oauthTokenKey != null && oauthTokenSecret != null
|
fun isApiLoginValid() = oauthTokenKey != null && oauthTokenSecret != null && oauthTokenIsUser
|
||||||
|
|
||||||
override fun satisfyLoginMethods() {
|
override fun satisfyLoginMethods() {
|
||||||
loginMethods.clear()
|
loginMethods.clear()
|
||||||
@ -25,7 +25,7 @@ class DataUsos(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun generateUserCode() = "USOS:TEST"
|
override fun generateUserCode() = "$schoolId:${studentNumber ?: studentId}"
|
||||||
|
|
||||||
var schoolId: String?
|
var schoolId: String?
|
||||||
get() { mSchoolId = mSchoolId ?: loginStore.getLoginData("schoolId", null); return mSchoolId }
|
get() { mSchoolId = mSchoolId ?: loginStore.getLoginData("schoolId", null); return mSchoolId }
|
||||||
@ -62,6 +62,11 @@ class DataUsos(
|
|||||||
set(value) { loginStore.putLoginData("oauthTokenSecret", value); mOauthTokenSecret = value }
|
set(value) { loginStore.putLoginData("oauthTokenSecret", value); mOauthTokenSecret = value }
|
||||||
private var mOauthTokenSecret: String? = null
|
private var mOauthTokenSecret: String? = null
|
||||||
|
|
||||||
|
var oauthTokenIsUser: Boolean
|
||||||
|
get() { mOauthTokenIsUser = mOauthTokenIsUser ?: loginStore.getLoginData("oauthTokenIsUser", false); return mOauthTokenIsUser ?: false }
|
||||||
|
set(value) { loginStore.putLoginData("oauthTokenIsUser", value); mOauthTokenIsUser = value }
|
||||||
|
private var mOauthTokenIsUser: Boolean? = null
|
||||||
|
|
||||||
var studentId: String?
|
var studentId: String?
|
||||||
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId }
|
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId }
|
||||||
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value }
|
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value }
|
||||||
|
@ -76,7 +76,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) {
|
|||||||
service: String,
|
service: String,
|
||||||
params: Map<String, Any>,
|
params: Map<String, Any>,
|
||||||
responseType: ResponseType,
|
responseType: ResponseType,
|
||||||
onSuccess: (data: T) -> Unit,
|
onSuccess: (data: T, response: Response?) -> Unit,
|
||||||
) {
|
) {
|
||||||
val url = "${data.instanceUrl}services/$service"
|
val url = "${data.instanceUrl}services/$service"
|
||||||
d(tag, "Request: Usos/Api - $url")
|
d(tag, "Request: Usos/Api - $url")
|
||||||
@ -123,10 +123,10 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) {
|
|||||||
private fun <T> getCallback(
|
private fun <T> getCallback(
|
||||||
tag: String,
|
tag: String,
|
||||||
responseType: ResponseType,
|
responseType: ResponseType,
|
||||||
onSuccess: (data: T) -> Unit,
|
onSuccess: (data: T, response: Response?) -> Unit,
|
||||||
) = when (responseType) {
|
) = when (responseType) {
|
||||||
ResponseType.OBJECT -> object : JsonCallbackHandler() {
|
ResponseType.OBJECT -> object : JsonCallbackHandler() {
|
||||||
override fun onSuccess(data: JsonObject?, response: Response?) {
|
override fun onSuccess(data: JsonObject?, response: Response) {
|
||||||
processResponse(response, data as T, onSuccess)
|
processResponse(response, data as T, onSuccess)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ResponseType.ARRAY -> object : JsonArrayCallbackHandler() {
|
ResponseType.ARRAY -> object : JsonArrayCallbackHandler() {
|
||||||
override fun onSuccess(data: JsonArray?, response: Response?) {
|
override fun onSuccess(data: JsonArray?, response: Response) {
|
||||||
processResponse(response, data as T, onSuccess)
|
processResponse(response, data as T, onSuccess)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ResponseType.PLAIN -> object : TextCallbackHandler() {
|
ResponseType.PLAIN -> object : TextCallbackHandler() {
|
||||||
override fun onSuccess(data: String?, response: Response?) {
|
override fun onSuccess(data: String?, response: Response) {
|
||||||
processResponse(response, data as T, onSuccess)
|
processResponse(response, data as T, onSuccess)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,11 +155,11 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun <T> processResponse(
|
private fun <T> processResponse(
|
||||||
response: Response?,
|
response: Response,
|
||||||
data: T,
|
data: T,
|
||||||
onSuccess: (data: T) -> Unit,
|
onSuccess: (data: T, response: Response?) -> Unit,
|
||||||
) {
|
) {
|
||||||
onSuccess(data)
|
onSuccess(data, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processError(
|
private fun processError(
|
||||||
|
@ -4,9 +4,18 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_NO_STUDENT_PROGRAMMES
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_USOS
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin
|
||||||
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.edziennik.usos.login.UsosLoginApi
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLoginApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
|
|
||||||
class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) {
|
class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) {
|
||||||
companion object {
|
companion object {
|
||||||
@ -16,8 +25,60 @@ class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) {
|
|||||||
private val api = UsosApi(data, null)
|
private val api = UsosApi(data, null)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
UsosLoginApi(data) {
|
val loginStoreId = data.loginStore.id
|
||||||
|
val loginStoreType = LOGIN_TYPE_USOS
|
||||||
|
var firstProfileId = loginStoreId
|
||||||
|
|
||||||
|
UsosLoginApi(data) {
|
||||||
|
api.apiRequest<JsonObject>(
|
||||||
|
tag = TAG,
|
||||||
|
service = "users/user",
|
||||||
|
params = mapOf(
|
||||||
|
"fields" to listOf(
|
||||||
|
"id",
|
||||||
|
"first_name",
|
||||||
|
"last_name",
|
||||||
|
"student_number",
|
||||||
|
"student_programmes" to listOf(
|
||||||
|
"programme" to listOf("id"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
responseType = UsosApi.ResponseType.OBJECT,
|
||||||
|
) { json, response ->
|
||||||
|
val programmes = json.getJsonArray("student_programmes")
|
||||||
|
if (programmes.isNullOrEmpty()) {
|
||||||
|
data.error(ApiError(TAG, ERROR_USOS_NO_STUDENT_PROGRAMMES)
|
||||||
|
.withApiResponse(json)
|
||||||
|
.withResponse(response))
|
||||||
|
return@apiRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
val firstName = json.getString("first_name")
|
||||||
|
val lastName = json.getString("last_name")
|
||||||
|
val studentName = buildFullName(firstName, lastName)
|
||||||
|
|
||||||
|
val profile = Profile(
|
||||||
|
id = firstProfileId++,
|
||||||
|
loginStoreId = loginStoreId, loginStoreType = loginStoreType,
|
||||||
|
name = studentName,
|
||||||
|
subname = data.schoolId,
|
||||||
|
studentNameLong = studentName,
|
||||||
|
studentNameShort = studentName.getShortName(),
|
||||||
|
accountName = null, // student account
|
||||||
|
studentData = JsonObject(
|
||||||
|
"studentId" to json.getInt("id"),
|
||||||
|
"studentNumber" to json.getInt("student_number"),
|
||||||
|
),
|
||||||
|
).also {
|
||||||
|
it.studentClassName = programmes.getJsonObject(0).getJsonObject("programme").getString("id")
|
||||||
|
}
|
||||||
|
|
||||||
|
EventBus.getDefault().postSticky(
|
||||||
|
FirstLoginFinishedEvent(listOf(profile), data.loginStore),
|
||||||
|
)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_OAUTH_LOGIN_REQUEST
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.USOS_API_OAUTH_REDIRECT_URL
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.USOS_API_SCOPES
|
|
||||||
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.models.ApiError
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
@ -21,19 +19,21 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) {
|
|||||||
private const val TAG = "UsosLoginApi"
|
private const val TAG = "UsosLoginApi"
|
||||||
}
|
}
|
||||||
|
|
||||||
init { run {
|
private val api = UsosApi(data, null)
|
||||||
if (data.isApiLoginValid()) {
|
|
||||||
onSuccess()
|
init {
|
||||||
} else if (data.oauthLoginResponse != null) {
|
run {
|
||||||
login()
|
if (data.isApiLoginValid()) {
|
||||||
} else {
|
onSuccess()
|
||||||
authorize()
|
} else if (data.oauthLoginResponse != null) {
|
||||||
|
login()
|
||||||
|
} else {
|
||||||
|
authorize()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
}
|
||||||
|
|
||||||
private fun authorize() {
|
private fun authorize() {
|
||||||
val api = UsosApi(data, null)
|
|
||||||
|
|
||||||
api.apiRequest<String>(
|
api.apiRequest<String>(
|
||||||
tag = TAG,
|
tag = TAG,
|
||||||
service = "oauth/request_token",
|
service = "oauth/request_token",
|
||||||
@ -42,10 +42,11 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) {
|
|||||||
"scopes" to USOS_API_SCOPES,
|
"scopes" to USOS_API_SCOPES,
|
||||||
),
|
),
|
||||||
responseType = UsosApi.ResponseType.PLAIN,
|
responseType = UsosApi.ResponseType.PLAIN,
|
||||||
) {
|
) { text, _ ->
|
||||||
val response = it.fromQueryString()
|
val authorizeData = text.fromQueryString()
|
||||||
data.oauthTokenKey = response["oauth_token"]
|
data.oauthTokenKey = authorizeData["oauth_token"]
|
||||||
data.oauthTokenSecret = response["oauth_token_secret"]
|
data.oauthTokenSecret = authorizeData["oauth_token_secret"]
|
||||||
|
data.oauthTokenIsUser = false
|
||||||
|
|
||||||
val authUrl = "${data.instanceUrl}services/oauth/authorize"
|
val authUrl = "${data.instanceUrl}services/oauth/authorize"
|
||||||
val authParams = mapOf(
|
val authParams = mapOf(
|
||||||
@ -63,6 +64,42 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun login() {
|
private fun login() {
|
||||||
d(TAG, "Login to ${data.schoolId} with ${data.oauthLoginResponse} (${data.oauthTokenSecret})")
|
d(TAG, "Login to ${data.schoolId} with ${data.oauthLoginResponse}")
|
||||||
|
|
||||||
|
val authorizeResponse = data.oauthLoginResponse?.fromQueryString()
|
||||||
|
?: return // checked in init {}
|
||||||
|
if (authorizeResponse["oauth_token"] != data.oauthTokenKey) {
|
||||||
|
// got different token
|
||||||
|
data.error(ApiError(TAG, ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN)
|
||||||
|
.withApiResponse(data.oauthLoginResponse))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val verifier = authorizeResponse["oauth_verifier"]
|
||||||
|
if (verifier.isNullOrBlank()) {
|
||||||
|
data.error(ApiError(TAG, ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE)
|
||||||
|
.withApiResponse(data.oauthLoginResponse))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
api.apiRequest<String>(
|
||||||
|
tag = TAG,
|
||||||
|
service = "oauth/access_token",
|
||||||
|
params = mapOf(
|
||||||
|
"oauth_verifier" to verifier,
|
||||||
|
),
|
||||||
|
responseType = UsosApi.ResponseType.PLAIN,
|
||||||
|
) { text, response ->
|
||||||
|
val accessData = text.fromQueryString()
|
||||||
|
data.oauthTokenKey = accessData["oauth_token"]
|
||||||
|
data.oauthTokenSecret = accessData["oauth_token_secret"]
|
||||||
|
data.oauthTokenIsUser = data.oauthTokenKey != null && data.oauthTokenSecret != null
|
||||||
|
|
||||||
|
if (!data.oauthTokenIsUser)
|
||||||
|
data.error(ApiError(TAG, ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE)
|
||||||
|
.withApiResponse(text)
|
||||||
|
.withResponse(response))
|
||||||
|
else
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import com.google.gson.JsonElement
|
|||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import com.google.gson.JsonParser
|
import com.google.gson.JsonParser
|
||||||
import com.google.gson.JsonPrimitive
|
import com.google.gson.JsonPrimitive
|
||||||
|
import kotlin.contracts.ExperimentalContracts
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
fun JsonObject?.get(key: String): JsonElement? = this?.get(key)
|
fun JsonObject?.get(key: String): JsonElement? = this?.get(key)
|
||||||
|
|
||||||
@ -93,7 +95,13 @@ fun JsonArray(vararg properties: Any?): JsonArray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun JsonArray?.isNullOrEmpty(): Boolean = (this?.size() ?: 0) == 0
|
@OptIn(ExperimentalContracts::class)
|
||||||
|
fun JsonArray?.isNullOrEmpty(): Boolean {
|
||||||
|
contract {
|
||||||
|
returns(false) implies (this@isNullOrEmpty != null)
|
||||||
|
}
|
||||||
|
return this == null || this.isEmpty
|
||||||
|
}
|
||||||
operator fun JsonArray.plusAssign(o: JsonElement) = this.add(o)
|
operator fun JsonArray.plusAssign(o: JsonElement) = this.add(o)
|
||||||
operator fun JsonArray.plusAssign(o: String) = this.add(o)
|
operator fun JsonArray.plusAssign(o: String) = this.add(o)
|
||||||
operator fun JsonArray.plusAssign(o: Char) = this.add(o)
|
operator fun JsonArray.plusAssign(o: Char) = this.add(o)
|
||||||
|
@ -355,6 +355,7 @@ fun Map<String, String>.toQueryString() = this
|
|||||||
.joinToString("&") { "${it.first}=${it.second}" }
|
.joinToString("&") { "${it.first}=${it.second}" }
|
||||||
|
|
||||||
fun String.fromQueryString() = this
|
fun String.fromQueryString() = this
|
||||||
|
.substringAfter('?')
|
||||||
.split("&")
|
.split("&")
|
||||||
.map { it.split("=") }
|
.map { it.split("=") }
|
||||||
.associate { it[0].urlDecode() to it[1].urlDecode() }
|
.associate { it[0].urlDecode() to it[1].urlDecode() }
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2022-10-14.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.ui.dialogs
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
|
||||||
import android.webkit.WebView
|
|
||||||
import android.webkit.WebViewClient
|
|
||||||
import android.widget.FrameLayout
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.core.view.updateLayoutParams
|
|
||||||
import pl.szczodrzynski.edziennik.R
|
|
||||||
import pl.szczodrzynski.edziennik.ext.dp
|
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.base.ViewDialog
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
|
||||||
|
|
||||||
class OAuthLoginDialog(
|
|
||||||
activity: AppCompatActivity,
|
|
||||||
private val authorizeUrl: String,
|
|
||||||
private val redirectUrl: String,
|
|
||||||
private val onSuccess: (responseUrl: String) -> Unit,
|
|
||||||
private val onFailure: (() -> Unit)?,
|
|
||||||
onShowListener: ((tag: String) -> Unit)? = null,
|
|
||||||
onDismissListener: ((tag: String) -> Unit)? = null,
|
|
||||||
) : ViewDialog<WebView>(activity, onShowListener, onDismissListener) {
|
|
||||||
|
|
||||||
override val TAG = "OAuthLoginDialog"
|
|
||||||
|
|
||||||
override fun getTitleRes() = R.string.oauth_dialog_title
|
|
||||||
override fun getPositiveButtonText() = R.string.close
|
|
||||||
|
|
||||||
private var isSuccessful = false
|
|
||||||
|
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
|
||||||
override fun getRootView(): WebView {
|
|
||||||
val webView = WebView(activity)
|
|
||||||
webView.webViewClient = object : WebViewClient() {
|
|
||||||
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
|
|
||||||
d(TAG, "Navigating to $url")
|
|
||||||
if (url.startsWith(redirectUrl)) {
|
|
||||||
isSuccessful = true
|
|
||||||
onSuccess(url)
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
webView.settings.javaScriptEnabled = true
|
|
||||||
return webView
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun onShow() {
|
|
||||||
dialog.window?.setLayout(MATCH_PARENT, MATCH_PARENT)
|
|
||||||
root.minimumHeight = activity.windowManager.defaultDisplay?.height?.div(2) ?: 300.dp
|
|
||||||
root.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
|
|
||||||
root.loadUrl(authorizeUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDismiss() {
|
|
||||||
root.stopLoading()
|
|
||||||
if (!isSuccessful)
|
|
||||||
onFailure?.invoke()
|
|
||||||
}
|
|
||||||
}
|
|
@ -324,7 +324,7 @@ object LoginInfo {
|
|||||||
Mode(
|
Mode(
|
||||||
loginMode = LOGIN_MODE_USOS_OAUTH,
|
loginMode = LOGIN_MODE_USOS_OAUTH,
|
||||||
name = R.string.login_mode_usos_oauth,
|
name = R.string.login_mode_usos_oauth,
|
||||||
icon = R.drawable.login_logo_usos,
|
icon = R.drawable.login_mode_usos_api,
|
||||||
guideText = R.string.login_mode_usos_oauth_guide,
|
guideText = R.string.login_mode_usos_oauth_guide,
|
||||||
isPlatformSelection = true,
|
isPlatformSelection = true,
|
||||||
credentials = listOf(),
|
credentials = listOf(),
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-15.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.login.oauth
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
import android.webkit.WebView
|
||||||
|
import android.webkit.WebViewClient
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
|
class OAuthLoginActivity : AppCompatActivity() {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "OAuthLoginActivity"
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isSuccessful = false
|
||||||
|
|
||||||
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
setTitle(R.string.oauth_dialog_title)
|
||||||
|
|
||||||
|
val authorizeUrl = intent.getStringExtra("authorizeUrl") ?: return
|
||||||
|
val redirectUrl = intent.getStringExtra("redirectUrl") ?: return
|
||||||
|
|
||||||
|
val webView = WebView(this)
|
||||||
|
webView.webViewClient = object : WebViewClient() {
|
||||||
|
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
|
||||||
|
d(TAG, "Navigating to $url")
|
||||||
|
if (url.startsWith(redirectUrl)) {
|
||||||
|
isSuccessful = true
|
||||||
|
EventBus.getDefault().post(OAuthLoginResult(
|
||||||
|
isError = false,
|
||||||
|
responseUrl = url,
|
||||||
|
))
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
webView.settings.javaScriptEnabled = true
|
||||||
|
webView.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
|
||||||
|
setContentView(webView)
|
||||||
|
|
||||||
|
webView.loadUrl(authorizeUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
if (!isSuccessful)
|
||||||
|
EventBus.getDefault().post(OAuthLoginResult(
|
||||||
|
isError = false,
|
||||||
|
responseUrl = null,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-15.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.login.oauth
|
||||||
|
|
||||||
|
data class OAuthLoginResult(
|
||||||
|
val isError: Boolean,
|
||||||
|
val responseUrl: String?,
|
||||||
|
)
|
@ -11,6 +11,8 @@ import android.os.Bundle
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import org.greenrobot.eventbus.Subscribe
|
||||||
|
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
|
||||||
@ -21,7 +23,8 @@ 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.ui.captcha.LibrusCaptchaDialog
|
import pl.szczodrzynski.edziennik.ui.captcha.LibrusCaptchaDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.OAuthLoginDialog
|
import pl.szczodrzynski.edziennik.ui.login.oauth.OAuthLoginActivity
|
||||||
|
import pl.szczodrzynski.edziennik.ui.login.oauth.OAuthLoginResult
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
class UserActionManager(val app: App) {
|
class UserActionManager(val app: App) {
|
||||||
@ -143,25 +146,35 @@ class UserActionManager(val app: App) {
|
|||||||
return false
|
return false
|
||||||
val extras = params.getBundle("extras")
|
val extras = params.getBundle("extras")
|
||||||
val storeKey = params.getString("responseStoreKey") ?: return false
|
val storeKey = params.getString("responseStoreKey") ?: return false
|
||||||
|
params.getString("authorizeUrl") ?: return false
|
||||||
|
params.getString("redirectUrl") ?: return false
|
||||||
|
|
||||||
OAuthLoginDialog(
|
var listener: Any? = null
|
||||||
activity = activity,
|
listener = object {
|
||||||
authorizeUrl = params.getString("authorizeUrl") ?: return false,
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
redirectUrl = params.getString("redirectUrl") ?: return false,
|
fun onOAuthLoginResult(result: OAuthLoginResult) {
|
||||||
onSuccess = { responseUrl ->
|
EventBus.getDefault().unregister(listener)
|
||||||
val args = Bundle(
|
when {
|
||||||
storeKey to responseUrl,
|
result.isError -> onFailure?.invoke()
|
||||||
)
|
result.responseUrl != null -> {
|
||||||
if (extras != null)
|
val args = Bundle(
|
||||||
args.putAll(extras)
|
storeKey to result.responseUrl,
|
||||||
|
)
|
||||||
|
if (extras != null)
|
||||||
|
args.putAll(extras)
|
||||||
|
|
||||||
if (onSuccess != null)
|
if (onSuccess != null)
|
||||||
onSuccess(args)
|
onSuccess(args)
|
||||||
else
|
else
|
||||||
EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity)
|
EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity)
|
||||||
},
|
}
|
||||||
onFailure = onFailure,
|
}
|
||||||
).show()
|
}
|
||||||
|
}
|
||||||
|
EventBus.getDefault().register(listener)
|
||||||
|
|
||||||
|
val intent = Intent(activity, OAuthLoginActivity::class.java).putExtras(params)
|
||||||
|
activity.startActivity(intent)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
BIN
app/src/main/res/drawable/login_mode_usos_api.png
Normal file
BIN
app/src/main/res/drawable/login_mode_usos_api.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
Loading…
x
Reference in New Issue
Block a user