illegal token checking

fixes
This commit is contained in:
2021-09-17 16:25:26 +03:00
parent a3a282c32c
commit d1ed98691c
57 changed files with 968 additions and 251 deletions
@@ -5,7 +5,7 @@ object VKConstants {
const val GROUP_FIELDS = "description,members_count,counters,status,verified"
const val USER_FIELDS =
"photo_50,photo_100,photo_200,status,screen_name,online,online_mobile,last_seen,verified,sex"
"photo_50,photo_100,photo_200,status,screen_name,online,online_mobile,last_seen,verified,sex,online_info"
const val API_VERSION = "5.132"
@@ -3,7 +3,12 @@ package com.meloda.fast.api
import org.json.JSONObject
import java.io.IOException
class VKException(var url: String = "", var description: String = "", var error: String) :
open class VKException(
var url: String = "",
var code: Int = -1,
var description: String = "",
var error: String
) :
IOException(description) {
var captcha: Pair<String, String>? = null
@@ -13,18 +13,18 @@ import com.meloda.fast.api.model.VkUser
import com.meloda.fast.api.model.attachments.*
import com.meloda.fast.api.model.base.BaseVkMessage
import com.meloda.fast.api.model.base.attachments.BaseVkAttachmentItem
import com.meloda.fast.api.network.VKErrors
import com.meloda.fast.api.network.VkErrors
object VkUtils {
fun isValidationRequired(throwable: Throwable): Boolean {
if (throwable !is VKException) return false
return throwable.error == VKErrors.NEED_VALIDATION
return throwable.error == VkErrors.NEED_VALIDATION
}
fun isCaptchaRequired(throwable: Throwable): Boolean {
if (throwable !is VKException) return false
return throwable.error == VKErrors.NEED_CAPTCHA
return throwable.error == VkErrors.NEED_CAPTCHA
}
fun prepareMessageText(text: String): String {
@@ -94,9 +94,7 @@ object VkUtils {
}
BaseVkAttachmentItem.AttachmentType.STICKER -> {
val sticker = baseAttachment.sticker ?: continue
attachments += VkSticker(
link = sticker.images[0].url
)
attachments += sticker.asVkSticker()
}
BaseVkAttachmentItem.AttachmentType.GIFT -> {
val gift = baseAttachment.gift ?: continue
@@ -275,9 +273,9 @@ object VkUtils {
else -> return null
} ?: return null
val actionMessage = message.actionMessage ?: return null
val actionMessage = message.actionMessage
"$prefix pinned message «$actionMessage»"
"$prefix pinned message ${if (actionMessage == null) "" else "«$actionMessage»"}".trim()
}
VkMessage.Action.CHAT_UNPIN_MESSAGE -> {
val prefix = when {
@@ -1,11 +1,11 @@
package com.meloda.fast.api.base
import com.google.gson.annotations.SerializedName
import java.io.IOException
import com.meloda.fast.api.VKException
data class ApiError(
@SerializedName("error_code")
val errorCode: Int,
@SerializedName("error_msg")
override var message: String
) : IOException()
) : VKException(error = message, code = errorCode)
@@ -33,8 +33,8 @@ data class VkConversation(
fun isUser() = type == "user"
fun isGroup() = type == "group"
fun isInUnread() = inRead != lastMessageId
fun isOutUnread() = outRead != lastMessageId
fun isInUnread() = inRead < lastMessageId
fun isOutUnread() = outRead < lastMessageId
fun isUnread() = isInUnread() || isOutUnread()
@@ -12,8 +12,9 @@ data class VkGroup(
val id: Int,
val name: String,
val screenName: String,
val photo200: String?
): Parcelable {
val photo200: String?,
val membersCount: Int?
) : Parcelable {
override fun toString() = name.trim()
@@ -42,14 +42,31 @@ data class VkMessage(
fun isGroup() = fromId < 0
fun isRead(conversation: VkConversation) = conversation.outRead < id
fun isRead(conversation: VkConversation) =
if (isOut) conversation.outRead < id
else conversation.inRead < id
fun getPreparedAction(): Action? {
if (action == null) return null
return Action.parse(action)
}
fun changeId(id: Int) = VkMessage(
fun copyMessage(
id: Int = this.id,
text: String? = this.text,
isOut: Boolean = this.isOut,
peerId: Int = this.peerId,
fromId: Int = this.fromId,
date: Int = this.date,
randomId: Int = this.randomId,
action: String? = this.action,
actionMemberId: Int? = this.actionMemberId,
actionText: String? = this.actionText,
actionConversationMessageId: Int? = this.actionConversationMessageId,
actionMessage: String? = this.actionMessage,
geoType: String? = this.geoType,
important: Boolean = this.important
) = VkMessage(
id = id,
text = text,
isOut = isOut,
@@ -64,7 +81,10 @@ data class VkMessage(
actionMessage = actionMessage,
geoType = geoType,
important = important
)
).also {
it.attachments = attachments
it.forwards = forwards
}
enum class Action(val value: String) {
CHAT_CREATE("chat_create"),
@@ -13,9 +13,13 @@ data class VkUser(
val firstName: String,
val lastName: String,
val online: Boolean,
val photo200: String?
val photo200: String?,
val lastSeen: Int?,
val lastSeenStatus: String?
) : Parcelable {
override fun toString() = "$firstName $lastName".trim()
override fun toString() = fullName
val fullName get() = "$firstName $lastName".trim()
}
@@ -1,8 +1,23 @@
package com.meloda.fast.api.model.attachments
import com.meloda.fast.api.model.base.attachments.BaseVkSticker
import com.meloda.fast.api.model.base.attachments.StickerSize
import kotlinx.parcelize.Parcelize
@Parcelize
data class VkSticker(
val link: String
) : VkAttachment()
val id: Int,
val productId: Int,
val images: List<BaseVkSticker.Image>,
val backgroundImages: List<BaseVkSticker.Image>
) : VkAttachment() {
fun urlForSize(@StickerSize size: Int): String? {
for (image in images) {
if (image.width == size) return image.url
}
return null
}
}
@@ -25,14 +25,17 @@ data class BaseVkGroup(
@SerializedName("photo_100")
val photo100: String?,
@SerializedName("photo_200")
val photo200: String?
val photo200: String?,
@SerializedName("members_count")
val membersCount: Int?
) : Parcelable {
fun asVkGroup() = VkGroup(
id = -id,
name = name,
screenName = screenName,
photo200 = photo200
photo200 = photo200,
membersCount = membersCount
)
}
@@ -0,0 +1,12 @@
package com.meloda.fast.api.model.base
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class BaseVkLongPoll(
val server: String,
val key: String,
val ts: Int,
val pts: Int
) : Parcelable
@@ -52,7 +52,9 @@ data class BaseVkUser(
firstName = firstName,
lastName = lastName,
online = online == 1,
photo200 = photo200
photo200 = photo200,
lastSeen = onlineInfo?.lastSeen,
lastSeenStatus = onlineInfo?.status
)
}
@@ -1,7 +1,9 @@
package com.meloda.fast.api.model.base.attachments
import android.os.Parcelable
import androidx.annotation.IntDef
import com.google.gson.annotations.SerializedName
import com.meloda.fast.api.model.attachments.VkSticker
import kotlinx.parcelize.Parcelize
@Parcelize
@@ -18,6 +20,13 @@ data class BaseVkSticker(
val animations: List<Animation>?
) : Parcelable {
fun asVkSticker() = VkSticker(
id = stickerId,
productId = productId,
images = images,
backgroundImages = imagesWithBackground
)
@Parcelize
data class Image(
val width: Int,
@@ -31,5 +40,7 @@ data class BaseVkSticker(
val url: String
) : Parcelable
}
}
@IntDef(64, 128, 256, 352)
annotation class StickerSize
@@ -1,7 +1,6 @@
package com.meloda.fast.api.model.request
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
@@ -59,7 +58,6 @@ data class MessagesSendRequest(
@Parcelize
data class MessagesMarkAsImportantRequest(
@SerializedName("message_ids")
val messagesIds: List<Int>,
val important: Boolean
) : Parcelable {
@@ -70,4 +68,17 @@ data class MessagesMarkAsImportantRequest(
"important" to (if (important) 1 else 0).toString()
)
}
@Parcelize
data class MessagesGetLongPollServerRequest(
val needPts: Boolean,
val version: Int
) : Parcelable {
val map
get() = mutableMapOf(
"need_pts" to (if (needPts) 1 else 0).toString(),
"version" to version.toString()
)
}
@@ -1,6 +1,6 @@
package com.meloda.fast.api.network
object ErrorCodes {
object VkErrorCodes {
const val UNKNOWN_ERROR = 1
const val APP_DISABLED = 2
const val UNKNOWN_METHOD = 3
@@ -41,7 +41,7 @@ object ErrorCodes {
const val ACCESS_TO_DOC_DENIED = 1153
}
object VKErrors {
object VkErrors {
const val UNKNOWN = "unknown_error"
const val NEED_VALIDATION = "need_validation"
@@ -1,10 +1,9 @@
package com.meloda.fast.api.network
import com.meloda.fast.api.VKException
import com.meloda.fast.api.base.ApiResponse
import okhttp3.Request
import okio.IOException
import okio.Timeout
import org.json.JSONObject
import retrofit2.*
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
@@ -76,11 +75,16 @@ internal class ResultCall<T>(proxy: Call<T>) : CallDelegate<T, Answer<T>>(proxy)
) : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
val result: Answer<T> = if (response.isSuccessful)
Answer.Success(response.body() as T)
else Answer.Error(IOException(response.errorBody()?.string() ?: ""))
if (result is Answer.Error) if (checkErrors(call, result)) return
val result: Answer<T> =
if (response.isSuccessful) {
val baseBody = response.body()
if (baseBody !is ApiResponse<*>) Answer.Success(baseBody as T)
else {
val body = baseBody as ApiResponse<*>
if (body.error != null) Answer.Error(body.error)
else Answer.Success(body as T)
}
} else Answer.Error(IOException(response.errorBody()?.string() ?: ""))
callback.onResponse(proxy, Response.success(result))
}
@@ -91,23 +95,6 @@ internal class ResultCall<T>(proxy: Call<T>) : CallDelegate<T, Answer<T>>(proxy)
Response.success(Answer.Error(throwable = error))
)
}
private fun checkErrors(call: Call<T>, result: Answer.Error): Boolean {
val json = JSONObject(result.throwable.message ?: "{}")
return if (json.has("error")) {
val error = json.optString("error", "")
val description = json.optString("error_description", "")
val exception = VKException(
error = error,
description = description,
).also { it.json = json }
onFailure(call, exception)
true
} else false
}
}
override fun timeout(): Timeout {
@@ -22,6 +22,8 @@ object VKUrls {
const val GetHistory = "$API/messages.getHistory"
const val Send = "$API/messages.send"
const val MarkAsImportant = "$API/messages.markAsImportant"
const val GetLongPollServer = "$API/messages.getLongPollServer"
const val GetLongPollHistory = "$API/messages.getLongPollHistory"
}
@@ -1,6 +1,7 @@
package com.meloda.fast.api.network.datasource
import com.meloda.fast.api.model.request.MessagesGetHistoryRequest
import com.meloda.fast.api.model.request.MessagesGetLongPollServerRequest
import com.meloda.fast.api.model.request.MessagesMarkAsImportantRequest
import com.meloda.fast.api.model.request.MessagesSendRequest
import com.meloda.fast.api.network.repo.MessagesRepo
@@ -21,4 +22,7 @@ class MessagesDataSource @Inject constructor(
suspend fun markAsImportant(params: MessagesMarkAsImportantRequest) =
repo.markAsImportant(params.map)
suspend fun getLongPollServer(params: MessagesGetLongPollServerRequest) =
repo.getLongPollServer(params.map)
}
@@ -0,0 +1,18 @@
package com.meloda.fast.api.network.repo
import com.meloda.fast.api.base.ApiResponse
import com.meloda.fast.api.network.Answer
import org.json.JSONObject
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.QueryMap
interface LongPollRepo {
@GET("https://{serverUrl}")
suspend fun getResponse(
@Path("serverUrl") serverUrl: String,
@QueryMap params: Map<String, String>
): Answer<ApiResponse<JSONObject>>
}
@@ -1,6 +1,7 @@
package com.meloda.fast.api.network.repo
import com.meloda.fast.api.base.ApiResponse
import com.meloda.fast.api.model.base.BaseVkLongPoll
import com.meloda.fast.api.model.response.MessagesGetHistoryResponse
import com.meloda.fast.api.network.Answer
import com.meloda.fast.api.network.VKUrls
@@ -22,4 +23,8 @@ interface MessagesRepo {
@POST(VKUrls.Messages.MarkAsImportant)
suspend fun markAsImportant(@FieldMap params: Map<String, String>): Answer<ApiResponse<List<Int>>>
@FormUrlEncoded
@POST(VKUrls.Messages.GetLongPollServer)
suspend fun getLongPollServer(@FieldMap params: Map<String, String>): Answer<ApiResponse<BaseVkLongPoll>>
}