use nodeinfo whenever possible
This commit is contained in:
parent
360e40b7fa
commit
f8b3e1627a
@ -10,22 +10,15 @@ import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.h.pixeldroid.databinding.ActivityLoginBinding
|
||||
import com.h.pixeldroid.databinding.ActivityPostCreationBinding
|
||||
import com.h.pixeldroid.utils.BaseActivity
|
||||
import com.h.pixeldroid.utils.*
|
||||
import com.h.pixeldroid.utils.api.PixelfedAPI
|
||||
import com.h.pixeldroid.utils.api.objects.*
|
||||
import com.h.pixeldroid.utils.db.addUser
|
||||
import com.h.pixeldroid.utils.db.storeInstance
|
||||
import com.h.pixeldroid.utils.hasInternet
|
||||
import com.h.pixeldroid.utils.normalizeDomain
|
||||
import com.h.pixeldroid.utils.openUrl
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import okhttp3.HttpUrl
|
||||
import kotlinx.coroutines.*
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
/**
|
||||
Overview of the flow of the login process: (boxes are requests done in parallel,
|
||||
@ -125,11 +118,7 @@ class LoginActivity : BaseActivity() {
|
||||
|
||||
private fun registerAppToServer(normalizedDomain: String) {
|
||||
|
||||
try{
|
||||
HttpUrl.Builder().host(normalizedDomain.replace("https://", "")).scheme("https").build()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
return failedRegistration(getString(R.string.invalid_domain))
|
||||
}
|
||||
if(!validDomain(normalizedDomain)) failedRegistration(getString(R.string.invalid_domain))
|
||||
|
||||
hideKeyboard()
|
||||
loadingAnimation(true)
|
||||
@ -138,7 +127,6 @@ class LoginActivity : BaseActivity() {
|
||||
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
supervisorScope { }
|
||||
val credentialsDeferred: Deferred<Application?> = async {
|
||||
try {
|
||||
pixelfedAPI.registerApplication(
|
||||
@ -157,7 +145,6 @@ class LoginActivity : BaseActivity() {
|
||||
|
||||
val clientId = credentials?.client_id ?: return@launch failedRegistration()
|
||||
preferences.edit()
|
||||
.putString("domain", normalizedDomain)
|
||||
.putString("clientID", clientId)
|
||||
.putString("clientSecret", credentials.client_secret)
|
||||
.apply()
|
||||
@ -181,15 +168,39 @@ class LoginActivity : BaseActivity() {
|
||||
normalizedDomain: String,
|
||||
clientId: String,
|
||||
nodeInfoSchemaUrl: String
|
||||
) {
|
||||
val nodeInfo = try {
|
||||
) = coroutineScope {
|
||||
|
||||
val nodeInfo: NodeInfo = try {
|
||||
pixelfedAPI.nodeInfoSchema(nodeInfoSchemaUrl)
|
||||
} catch (exception: IOException) {
|
||||
return failedRegistration(getString(R.string.instance_error))
|
||||
return@coroutineScope failedRegistration(getString(R.string.instance_error))
|
||||
} catch (exception: HttpException) {
|
||||
return failedRegistration(getString(R.string.instance_error))
|
||||
return@coroutineScope failedRegistration(getString(R.string.instance_error))
|
||||
}
|
||||
|
||||
//TODO here check for api being activated, if not show dialog
|
||||
val domain: String = try {
|
||||
if (nodeInfo.hasInstanceEndpointInfo()) {
|
||||
storeInstance(db, nodeInfo)
|
||||
nodeInfo.metadata?.config?.site?.url!!
|
||||
} else {
|
||||
val instance: Instance = try {
|
||||
pixelfedAPI.instance()
|
||||
} catch (exception: IOException) {
|
||||
return@coroutineScope failedRegistration(getString(R.string.instance_error))
|
||||
} catch (exception: HttpException) {
|
||||
return@coroutineScope failedRegistration(getString(R.string.instance_error))
|
||||
}
|
||||
storeInstance(db, nodeInfo = null, instance = instance)
|
||||
instance.uri ?: return@coroutineScope failedRegistration(getString(R.string.instance_error))
|
||||
}
|
||||
} catch (e: IllegalArgumentException){
|
||||
return@coroutineScope failedRegistration(getString(R.string.instance_error))
|
||||
}
|
||||
|
||||
preferences.edit().putString("domain", domain).apply()
|
||||
|
||||
|
||||
if (!nodeInfo.software?.name.orEmpty().contains("pixelfed")) {
|
||||
val builder = AlertDialog.Builder(this@LoginActivity)
|
||||
builder.apply {
|
||||
@ -238,9 +249,6 @@ class LoginActivity : BaseActivity() {
|
||||
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val instanceDeferred = async {
|
||||
pixelfedAPI.instance()
|
||||
}
|
||||
val token = pixelfedAPI.obtainToken(
|
||||
clientId, clientSecret, "$oauthScheme://$PACKAGE_ID", SCOPE, code,
|
||||
"authorization_code"
|
||||
@ -248,20 +256,12 @@ class LoginActivity : BaseActivity() {
|
||||
if (token.access_token == null) {
|
||||
return@launch failedRegistration(getString(R.string.token_error))
|
||||
}
|
||||
|
||||
val instance = instanceDeferred.await()
|
||||
|
||||
if (instance.uri == null) {
|
||||
return@launch failedRegistration(getString(R.string.instance_error))
|
||||
}
|
||||
|
||||
storeInstance(db, instance)
|
||||
storeUser(
|
||||
token.access_token,
|
||||
token.refresh_token,
|
||||
clientId,
|
||||
clientSecret,
|
||||
instance.uri
|
||||
domain
|
||||
)
|
||||
wipeSharedSettings()
|
||||
} catch (exception: IOException) {
|
||||
|
@ -91,7 +91,7 @@ class PostCreationActivity : BaseActivity() {
|
||||
instances.filter { instanceDatabaseEntity ->
|
||||
instanceDatabaseEntity.uri.contains(user!!.instance_uri)
|
||||
}
|
||||
thisInstances.first().max_toot_chars
|
||||
thisInstances.first().maxStatusChars
|
||||
} else {
|
||||
Instance.DEFAULT_MAX_TOOT_CHARS
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.h.pixeldroid.R
|
||||
import okhttp3.HttpUrl
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
@ -22,6 +23,21 @@ fun hasInternet(context: Context): Boolean {
|
||||
return cm.activeNetwork != null
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if domain is valid or not
|
||||
*/
|
||||
fun validDomain(domain: String?): Boolean {
|
||||
domain?.apply {
|
||||
try {
|
||||
HttpUrl.Builder().host(replace("https://", "")).scheme("https").build()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
return false
|
||||
}
|
||||
} ?: return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun normalizeDomain(domain: String): String {
|
||||
return "https://" + domain
|
||||
.replace("http://", "")
|
||||
|
@ -11,6 +11,8 @@ data class Instance (
|
||||
val version: String?
|
||||
) {
|
||||
companion object {
|
||||
// Default max number of chars for Mastodon: used when their is no other value supplied by
|
||||
// either NodeInfo or the instance endpoint
|
||||
const val DEFAULT_MAX_TOOT_CHARS = 500
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package com.h.pixeldroid.utils.api.objects
|
||||
|
||||
import com.h.pixeldroid.utils.validDomain
|
||||
|
||||
/*
|
||||
See https://nodeinfo.diaspora.software/schema.html and https://pixelfed.social/api/nodeinfo/2.0.json
|
||||
A lot of attributes we don't need are omitted, if in the future they are needed we
|
||||
@ -11,8 +13,21 @@ data class NodeInfo (
|
||||
val software: Software?,
|
||||
val protocols: List<String>?,
|
||||
val openRegistrations: Boolean?,
|
||||
val metadata: PixelfedMetadata?
|
||||
val metadata: PixelfedMetadata?,
|
||||
){
|
||||
/**
|
||||
* Check if this NodeInfo has the fields we need or if we also need to look into the
|
||||
* /api/v1/instance endpoint
|
||||
* This only checks for values that might be in the /api/v1/instance endpoint.
|
||||
*/
|
||||
fun hasInstanceEndpointInfo(): Boolean {
|
||||
return validDomain(metadata?.config?.site?.url)
|
||||
&& !metadata?.config?.site?.name.isNullOrBlank()
|
||||
&& metadata?.config?.uploader?.max_caption_length?.toIntOrNull() != null
|
||||
}
|
||||
|
||||
|
||||
|
||||
data class Software(
|
||||
val name: String?,
|
||||
val version: String?
|
||||
@ -31,7 +46,8 @@ data class NodeInfo (
|
||||
val open_registration: Boolean?,
|
||||
val uploader: Uploader?,
|
||||
val activitypub: ActivityPub?,
|
||||
val features: Features?
|
||||
val features: Features?,
|
||||
val site: Site?
|
||||
){
|
||||
data class Uploader(
|
||||
val max_photo_size: String?,
|
||||
@ -55,6 +71,13 @@ data class NodeInfo (
|
||||
val stories: Boolean?,
|
||||
val video: Boolean?
|
||||
)
|
||||
|
||||
data class Site(
|
||||
val name: String?,
|
||||
val domain: String?,
|
||||
val url: String?,
|
||||
val description: String?
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,23 +4,16 @@ import com.h.pixeldroid.utils.db.entities.InstanceDatabaseEntity
|
||||
import com.h.pixeldroid.utils.db.entities.UserDatabaseEntity
|
||||
import com.h.pixeldroid.utils.api.objects.Account
|
||||
import com.h.pixeldroid.utils.api.objects.Instance
|
||||
import com.h.pixeldroid.utils.api.objects.NodeInfo
|
||||
import com.h.pixeldroid.utils.normalizeDomain
|
||||
|
||||
private fun normalizeOrNot(uri: String): String{
|
||||
return if(uri.startsWith("http://localhost")){
|
||||
uri
|
||||
} else {
|
||||
normalizeDomain(uri)
|
||||
}
|
||||
}
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
fun addUser(db: AppDatabase, account: Account, instance_uri: String, activeUser: Boolean = true,
|
||||
accessToken: String, refreshToken: String?, clientId: String, clientSecret: String) {
|
||||
db.userDao().insertUser(
|
||||
UserDatabaseEntity(
|
||||
user_id = account.id!!,
|
||||
//make sure not to normalize to https when localhost, to allow testing
|
||||
instance_uri = normalizeOrNot(instance_uri),
|
||||
instance_uri = normalizeDomain(instance_uri),
|
||||
username = account.username!!,
|
||||
display_name = account.getDisplayName(),
|
||||
avatar_static = account.avatar_static.orEmpty(),
|
||||
@ -33,14 +26,20 @@ fun addUser(db: AppDatabase, account: Account, instance_uri: String, activeUser:
|
||||
)
|
||||
}
|
||||
|
||||
fun storeInstance(db: AppDatabase, instance: Instance) {
|
||||
val maxTootChars = instance.max_toot_chars?.toInt() ?: Instance.DEFAULT_MAX_TOOT_CHARS
|
||||
val dbInstance = InstanceDatabaseEntity(
|
||||
//make sure not to normalize to https when localhost, to allow testing
|
||||
uri = normalizeOrNot(instance.uri.orEmpty()),
|
||||
title = instance.title.orEmpty(),
|
||||
max_toot_chars = maxTootChars,
|
||||
thumbnail = instance.thumbnail.orEmpty()
|
||||
)
|
||||
fun storeInstance(db: AppDatabase, nodeInfo: NodeInfo?, instance: Instance? = null) {
|
||||
val dbInstance: InstanceDatabaseEntity = nodeInfo?.run {
|
||||
InstanceDatabaseEntity(
|
||||
uri = normalizeDomain(metadata?.config?.site?.url!!),
|
||||
title = metadata.config.site.name!!,
|
||||
maxStatusChars = metadata.config.uploader?.max_caption_length!!.toInt(),
|
||||
)
|
||||
} ?: instance?.run {
|
||||
InstanceDatabaseEntity(
|
||||
uri = normalizeDomain(uri.orEmpty()),
|
||||
title = title.orEmpty(),
|
||||
maxStatusChars = max_toot_chars?.toInt() ?: Instance.DEFAULT_MAX_TOOT_CHARS,
|
||||
)
|
||||
} ?: throw IllegalArgumentException("Cannot store instance where both are null")
|
||||
|
||||
db.instanceDao().insertInstance(dbInstance)
|
||||
}
|
@ -6,8 +6,8 @@ import com.h.pixeldroid.utils.api.objects.Instance
|
||||
|
||||
@Entity(tableName = "instances")
|
||||
data class InstanceDatabaseEntity (
|
||||
@PrimaryKey var uri: String,
|
||||
var title: String = "",
|
||||
var max_toot_chars: Int = Instance.DEFAULT_MAX_TOOT_CHARS,
|
||||
var thumbnail: String = ""
|
||||
@PrimaryKey var uri: String,
|
||||
var title: String,
|
||||
var maxStatusChars: Int = Instance.DEFAULT_MAX_TOOT_CHARS,
|
||||
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user