235 lines
8.6 KiB
Kotlin
235 lines
8.6 KiB
Kotlin
package jp.juggler.subwaytooter.action
|
|
|
|
import android.app.Dialog
|
|
import android.os.Build
|
|
import jp.juggler.subwaytooter.*
|
|
import jp.juggler.subwaytooter.actmain.addColumn
|
|
import jp.juggler.subwaytooter.actmain.afterAccountVerify
|
|
import jp.juggler.subwaytooter.actmain.defaultInsertPosition
|
|
import jp.juggler.subwaytooter.api.*
|
|
import jp.juggler.subwaytooter.api.auth.Auth2Result
|
|
import jp.juggler.subwaytooter.api.auth.AuthBase
|
|
import jp.juggler.subwaytooter.api.entity.*
|
|
import jp.juggler.subwaytooter.column.ColumnType
|
|
import jp.juggler.subwaytooter.dialog.*
|
|
import jp.juggler.subwaytooter.dialog.DlgCreateAccount.Companion.showUserCreateDialog
|
|
import jp.juggler.subwaytooter.dialog.LoginForm.Companion.showLoginForm
|
|
import jp.juggler.subwaytooter.pref.*
|
|
import jp.juggler.subwaytooter.table.SavedAccount
|
|
import jp.juggler.subwaytooter.util.LinkHelper
|
|
import jp.juggler.subwaytooter.util.openBrowser
|
|
import jp.juggler.util.*
|
|
import jp.juggler.util.coroutine.launchMain
|
|
import jp.juggler.util.data.JsonObject
|
|
import jp.juggler.util.data.encodePercent
|
|
import jp.juggler.util.log.LogCategory
|
|
import jp.juggler.util.log.showToast
|
|
import jp.juggler.util.network.toFormRequestBody
|
|
import jp.juggler.util.network.toPost
|
|
import jp.juggler.util.ui.dismissSafe
|
|
import kotlinx.coroutines.*
|
|
|
|
private val log = LogCategory("Action_Account")
|
|
|
|
// Androidでは \w や \d がUnicode文字にマッチしてしまうので、IDEの警告を無視する
|
|
@Suppress("RegExpSimplifiable")
|
|
private val mailRegex =
|
|
"""\A[a-z0-9_+&*-]+(?:\.[a-z0-9_+&*-]+)*@(?:[a-z0-9-]+\.)+[a-z]{2,12}\z""".toRegex(
|
|
RegexOption.IGNORE_CASE
|
|
)
|
|
|
|
fun isAndroid7TlsBug(errorText: String) =
|
|
if (!errorText.contains("SSLHandshakeException")) {
|
|
false
|
|
} else {
|
|
val release = Build.VERSION.RELEASE
|
|
when {
|
|
release.startsWith("7.1.") -> false // 含まない 7.1.x
|
|
release.startsWith("7.1") -> true // 含む 7.1
|
|
release.startsWith("7.0") -> true // 含む 7.0
|
|
else -> false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* サイドメニューで「アカウントの追加」を選ぶと呼び出される。
|
|
* - サーバ名とアクションを指定するダイアログを開く。
|
|
* - 選択されたアクションに応じて分岐する。
|
|
*/
|
|
fun ActMain.accountAdd() {
|
|
showLoginForm { dialogHost, apiHost, serverInfo, action ->
|
|
launchMain {
|
|
try {
|
|
when (action) {
|
|
LoginForm.Action.Login -> {
|
|
val authUri = runApiTask2(apiHost) { it.authStep1() }
|
|
openBrowser(authUri)
|
|
dialogHost.dismissSafe()
|
|
}
|
|
LoginForm.Action.Pseudo -> {
|
|
val tootInstance = runApiTask2(apiHost) { TootInstance.getOrThrow(it) }
|
|
addPseudoAccount(apiHost, tootInstance)?.let { a ->
|
|
showToast(false, R.string.server_confirmed)
|
|
addColumn(defaultInsertPosition, a, ColumnType.LOCAL)
|
|
dialogHost.dismissSafe()
|
|
}
|
|
}
|
|
LoginForm.Action.Create ->
|
|
createUser(apiHost, serverInfo) { dialogHost.dismissSafe() }
|
|
LoginForm.Action.Token ->
|
|
accessTokenPrompt(apiHost) { dialogHost.dismissSafe() }
|
|
}
|
|
} catch (ex: Throwable) {
|
|
showApiError(ex)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private suspend fun ActMain.createUser(
|
|
apiHost: Host,
|
|
serverInfo: TootInstance?,
|
|
onComplete: (() -> Unit)? = null,
|
|
) {
|
|
serverInfo ?: error(
|
|
getString(
|
|
R.string.user_creation_not_supported,
|
|
apiHost.pretty,
|
|
"(unknown)",
|
|
)
|
|
)
|
|
|
|
fun TootApiClient.authUserCreate() =
|
|
AuthBase.findAuthForCreateUser(this, serverInfo)
|
|
?: error(
|
|
getString(
|
|
R.string.user_creation_not_supported,
|
|
apiHost.pretty,
|
|
serverInfo.instanceType.toString(),
|
|
)
|
|
)
|
|
|
|
// クライアント情報を取得。サーバ種別によってはユーザ作成ができないのでエラーとなる
|
|
val clientInfo = runApiTask2(apiHost) {
|
|
it.authUserCreate().prepareClient(serverInfo)
|
|
}
|
|
|
|
showUserCreateDialog(apiHost) { dialogCreate, params ->
|
|
launchMain {
|
|
try {
|
|
val auth2Result = runApiTask2(apiHost) {
|
|
it.authUserCreate().createUser(clientInfo = clientInfo, params = params)
|
|
}
|
|
if (afterAccountVerify(auth2Result)) {
|
|
dialogCreate.dismissSafe()
|
|
onComplete?.invoke()
|
|
}
|
|
} catch (ex: Throwable) {
|
|
showApiError(ex)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* アクセストークンを手動入力する。
|
|
*
|
|
* @param apiHost アクセストークンと関係のあるサーバのAPIホスト
|
|
* @param onComplete 非nullならアカウント認証が終わったタイミングで呼ばれる
|
|
*/
|
|
// アクセストークンの手動入力(更新)
|
|
fun ActMain.accessTokenPrompt(
|
|
apiHost: Host,
|
|
onComplete: (() -> Unit)? = null,
|
|
) {
|
|
DlgTextInput.show(
|
|
this,
|
|
getString(R.string.access_token_or_api_token),
|
|
null,
|
|
callback = object : DlgTextInput.Callback {
|
|
override fun onEmptyError() {
|
|
showToast(true, R.string.token_not_specified)
|
|
}
|
|
|
|
override fun onOK(dialog: Dialog, text: String) {
|
|
launchMain {
|
|
try {
|
|
val accessToken = text.trim()
|
|
val auth2Result = runApiTask2(apiHost) { client ->
|
|
val ti =
|
|
TootInstance.getExOrThrow(client, forceAccessToken = accessToken)
|
|
|
|
val tokenJson = JsonObject()
|
|
|
|
val userJson = client.verifyAccount(
|
|
accessToken,
|
|
outTokenInfo = tokenJson, // 更新される
|
|
misskeyVersion = ti.misskeyVersionMajor
|
|
)
|
|
|
|
val parser = TootParser(this, linkHelper = LinkHelper.create(ti))
|
|
|
|
Auth2Result(
|
|
tootInstance = ti,
|
|
tokenJson = tokenJson,
|
|
accountJson = userJson,
|
|
tootAccount = parser.account(userJson)
|
|
?: error("can't parse user information."),
|
|
)
|
|
}
|
|
if (afterAccountVerify(auth2Result)) {
|
|
dialog.dismissSafe()
|
|
onComplete?.invoke()
|
|
}
|
|
} catch (ex: Throwable) {
|
|
showApiError(ex)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
// アカウント設定
|
|
fun ActMain.accountOpenSetting() {
|
|
launchMain {
|
|
pickAccount(
|
|
bAllowPseudo = true,
|
|
bAuto = true,
|
|
message = getString(R.string.account_picker_open_setting)
|
|
)?.let {
|
|
arAccountSetting.launch(ActAccountSetting.createIntent(this@accountOpenSetting, it))
|
|
}
|
|
}
|
|
}
|
|
|
|
fun ActMain.accountResendConfirmMail(accessInfo: SavedAccount) {
|
|
DlgConfirmMail(
|
|
this,
|
|
accessInfo
|
|
) { email ->
|
|
launchMain {
|
|
runApiTask(accessInfo) { client ->
|
|
email?.let {
|
|
if (!mailRegex.matches(it)) {
|
|
return@runApiTask TootApiResult("email address is not valid.")
|
|
}
|
|
}
|
|
|
|
client.request(
|
|
"/api/v1/emails/confirmations",
|
|
ArrayList<String>().apply {
|
|
if (email != null) add("email=${email.encodePercent()}")
|
|
}.joinToString("&").toFormRequestBody().toPost()
|
|
)
|
|
}?.let { result ->
|
|
when (val error = result.error) {
|
|
null -> showToast(true, R.string.resend_confirm_mail_requested)
|
|
else -> showToast(true, error)
|
|
}
|
|
}
|
|
}
|
|
}.show()
|
|
}
|
|
|