[Messages] Implement Mobidziennik attachments. Fix multiplying attachments in UI.

This commit is contained in:
Kuba Szczodrzyński 2019-11-28 23:32:10 +01:00
parent 9b02c97926
commit c71b8f994c
13 changed files with 173 additions and 22 deletions

View File

@ -168,6 +168,8 @@ const val EXCEPTION_LIBRUS_API_REQUEST = 904
const val EXCEPTION_LIBRUS_SYNERGIA_REQUEST = 905
const val EXCEPTION_MOBIDZIENNIK_WEB_REQUEST = 906
const val EXCEPTION_VULCAN_API_REQUEST = 907
const val EXCEPTION_MOBIDZIENNIK_WEB_FILE_REQUEST = 908
const val EXCEPTION_LIBRUS_MESSAGES_FILE_REQUEST = 909
const val EXCEPTION_NOTIFY_AND_SYNC = 910
const val EXCEPTION_LIBRUS_MESSAGES_REQUEST = 911
const val EXCEPTION_IDZIENNIK_WEB_REQUEST = 912

View File

@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.api.v2.mobidziennik.Mobidziennik
import pl.szczodrzynski.edziennik.api.v2.template.Template
import pl.szczodrzynski.edziennik.api.v2.vulcan.Vulcan
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
@ -24,7 +25,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
fun syncProfileList(profileList: List<Int>) = EdziennikTask(-1, SyncProfileListRequest(profileList))
fun messageGet(profileId: Int, message: MessageFull) = EdziennikTask(profileId, MessageGetRequest(message))
fun announcementsRead(profileId: Int) = EdziennikTask(profileId, AnnouncementsReadRequest())
fun attachmentGet(profileId: Int, messageId: Long, attachmentId: Long, attachmentName: String) = EdziennikTask(profileId, AttachmentGetRequest(messageId, attachmentId, attachmentName))
fun attachmentGet(profileId: Int, message: Message, attachmentId: Long, attachmentName: String) = EdziennikTask(profileId, AttachmentGetRequest(message, attachmentId, attachmentName))
}
private lateinit var loginStore: LoginStore
@ -74,7 +75,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
is MessageGetRequest -> edziennikInterface?.getMessage(request.message)
is FirstLoginRequest -> edziennikInterface?.firstLogin()
is AnnouncementsReadRequest -> edziennikInterface?.markAllAnnouncementsAsRead()
is AttachmentGetRequest -> edziennikInterface?.getAttachment(request.messageId, request.attachmentId, request.attachmentName)
is AttachmentGetRequest -> edziennikInterface?.getAttachment(request.message, request.attachmentId, request.attachmentName)
}
}
@ -92,5 +93,5 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
data class SyncProfileListRequest(val profileList: List<Int>)
data class MessageGetRequest(val message: MessageFull)
class AnnouncementsReadRequest
data class AttachmentGetRequest(val messageId: Long, val attachmentId: Long, val attachmentName: String)
data class AttachmentGetRequest(val message: Message, val attachmentId: Long, val attachmentName: String)
}

View File

@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.api.v2.prepare
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
import pl.szczodrzynski.edziennik.utils.Utils.d
@ -70,7 +71,7 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
}
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
}

View File

@ -5,13 +5,14 @@
package pl.szczodrzynski.edziennik.api.v2.interfaces
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
interface EdziennikInterface {
fun sync(featureIds: List<Int>, viewId: Int? = null, arguments: JsonObject? = null)
fun getMessage(message: MessageFull)
fun markAllAnnouncementsAsRead()
fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String)
fun getAttachment(message: Message, attachmentId: Long, attachmentName: String)
fun firstLogin()
fun cancel()
}

View File

@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.LibrusFirstLogin
import pl.szczodrzynski.edziennik.api.v2.librus.login.*
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
import pl.szczodrzynski.edziennik.utils.Utils.d
@ -105,12 +106,12 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
}
}
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
LibrusLoginPortal(data) {
LibrusLoginApi(data) {
LibrusLoginSynergia(data) {
LibrusLoginMessages(data) {
LibrusMessagesGetAttachment(data, messageId, attachmentId, attachmentName) {
LibrusMessagesGetAttachment(data, message, attachmentId, attachmentName) {
completed()
}
}

View File

@ -196,7 +196,7 @@ open class LibrusMessages(open val data: DataLibrus) {
try {
onSuccess(file)
} catch (e: Exception) {
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_FILE_REQUEST)
.withResponse(response)
.withThrowable(e))
}
@ -206,7 +206,7 @@ open class LibrusMessages(open val data: DataLibrus) {
try {
onProgress(bytesWritten, bytesTotal)
} catch (e: Exception) {
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_FILE_REQUEST)
.withThrowable(e))
}
}

View File

@ -15,6 +15,7 @@ import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent.Companion.TYP
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusMessages
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
import pl.szczodrzynski.edziennik.get
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.Utils
@ -22,7 +23,7 @@ import java.io.File
import kotlin.coroutines.CoroutineContext
class LibrusMessagesGetAttachment(
override val data: DataLibrus, val messageId: Long, val attachmentId: Long,
override val data: DataLibrus, val message: Message, val attachmentId: Long,
val attachmentName: String, val onSuccess: () -> Unit) : LibrusMessages(data), CoroutineScope {
companion object {
const val TAG = "LibrusMessagesGetAttachment"
@ -38,7 +39,7 @@ class LibrusMessagesGetAttachment(
init {
messagesGet(TAG, "GetFileDownloadLink", parameters = mapOf(
"fileId" to attachmentId,
"msgId" to messageId,
"msgId" to message.id,
"archive" to 0
)) { doc ->
val downloadLink = doc.select("response GetFileDownloadLink downloadLink").text()
@ -55,8 +56,6 @@ class LibrusMessagesGetAttachment(
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
.withApiResponse(doc.toString()))
}
onSuccess()
}
}
@ -92,12 +91,11 @@ class LibrusMessagesGetAttachment(
private fun downloadAttachment(attachmentKey: String) {
val targetFile = File(Utils.getStorageDir(), attachmentName)
sandboxGetFile(TAG, "CSDownload&singleUseKey=$attachmentKey",
targetFile, { file ->
sandboxGetFile(TAG, "CSDownload&singleUseKey=$attachmentKey", targetFile, { file ->
val event = AttachmentGetEvent(
profileId,
messageId,
message.id,
attachmentId,
TYPE_FINISHED,
file.absolutePath
@ -108,10 +106,12 @@ class LibrusMessagesGetAttachment(
EventBus.getDefault().post(event)
onSuccess()
}) { written, _ ->
val event = AttachmentGetEvent(
profileId,
messageId,
message.id,
attachmentId,
TYPE_PROGRESS,
bytesWritten = written

View File

@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikData
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.web.MobidziennikWebGetAttachment
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.web.MobidziennikWebGetMessage
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.firstlogin.MobidziennikFirstLogin
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.login.MobidziennikLogin
@ -18,6 +19,7 @@ import pl.szczodrzynski.edziennik.api.v2.mobidziennikLoginMethods
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.api.v2.prepare
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
import pl.szczodrzynski.edziennik.utils.Utils.d
@ -76,8 +78,12 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
}
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
MobidziennikLoginWeb(data) {
MobidziennikWebGetAttachment(data, message, attachmentId, attachmentName) {
completed()
}
}
}
override fun firstLogin() {

View File

@ -6,12 +6,14 @@ package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data
import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response
import im.wangchao.mhttp.callback.FileCallbackHandler
import im.wangchao.mhttp.callback.TextCallbackHandler
import okhttp3.Cookie
import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.utils.Utils.d
import java.io.File
open class MobidziennikWeb(open val data: DataMobidziennik) {
companion object {
@ -93,4 +95,77 @@ open class MobidziennikWeb(open val data: DataMobidziennik) {
.build()
.enqueue()
}
fun webGetFile(tag: String, action: String, targetFile: File, onSuccess: (file: File) -> Unit,
onProgress: (written: Long, total: Long) -> Unit) {
val url = "https://${data.loginServerName}.mobidziennik.pl$action"
d(tag, "Request: Mobidziennik/Web - $url")
if (data.webSessionKey == null) {
data.error(TAG, ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY)
return
}
if (data.webSessionValue == null) {
data.error(TAG, ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE)
return
}
if (data.webServerId == null) {
data.error(TAG, ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID)
return
}
val callback = object : FileCallbackHandler(targetFile) {
override fun onSuccess(file: File?, response: Response?) {
if (file == null) {
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
.withResponse(response))
return
}
try {
onSuccess(file)
} catch (e: Exception) {
data.error(ApiError(tag, EXCEPTION_MOBIDZIENNIK_WEB_FILE_REQUEST)
.withResponse(response)
.withThrowable(e))
}
}
override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
try {
onProgress(bytesWritten, bytesTotal)
} catch (e: Exception) {
data.error(ApiError(tag, EXCEPTION_MOBIDZIENNIK_WEB_FILE_REQUEST)
.withThrowable(e))
}
}
override fun onFailure(response: Response?, throwable: Throwable?) {
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
}
}
data.app.cookieJar.saveFromResponse(null, listOf(
Cookie.Builder()
.name(data.webSessionKey!!)
.value(data.webSessionValue!!)
.domain("${data.loginServerName}.mobidziennik.pl")
.secure().httpOnly().build(),
Cookie.Builder()
.name("SERVERID")
.value(data.webServerId!!)
.domain("${data.loginServerName}.mobidziennik.pl")
.secure().httpOnly().build()
))
Request.builder()
.url(url)
.userAgent(MOBIDZIENNIK_USER_AGENT)
.callback(callback)
.build()
.enqueue()
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-28.
*/
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.web
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.api.v2.events.AttachmentGetEvent
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikWeb
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
import pl.szczodrzynski.edziennik.utils.Utils
import java.io.File
class MobidziennikWebGetAttachment(
override val data: DataMobidziennik, val message: Message, val attachmentId: Long,
val attachmentName: String, val onSuccess: () -> Unit) : MobidziennikWeb(data) {
companion object {
private const val TAG = "MobidziennikWebGetAttachment"
}
init {
val targetFile = File(Utils.getStorageDir(), attachmentName)
val typeUrl = if (message.type == Message.TYPE_SENT)
"wiadwyslana"
else
"wiadodebrana"
webGetFile(TAG, "/dziennik/$typeUrl/?id=${message.id}&zalacznik=$attachmentId", targetFile, { file ->
val event = AttachmentGetEvent(
profileId,
message.id,
attachmentId,
AttachmentGetEvent.TYPE_FINISHED,
file.absolutePath
)
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.messageId}_${event.attachmentId}")
Utils.writeStringToFile(attachmentDataFile, event.fileName)
EventBus.getDefault().post(event)
onSuccess()
}) { written, _ ->
// TODO make use of bytesTotal
val event = AttachmentGetEvent(
profileId,
message.id,
attachmentId,
AttachmentGetEvent.TYPE_PROGRESS,
bytesWritten = written
)
EventBus.getDefault().post(event)
}
}
}

View File

@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.api.v2.template.firstlogin.TemplateFirstLogin
import pl.szczodrzynski.edziennik.api.v2.template.login.TemplateLogin
import pl.szczodrzynski.edziennik.api.v2.templateLoginMethods
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
import pl.szczodrzynski.edziennik.utils.Utils.d
@ -70,7 +71,7 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore,
}
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
}

View File

@ -18,6 +18,7 @@ import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLogin
import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLoginApi
import pl.szczodrzynski.edziennik.api.v2.vulcanLoginMethods
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
import pl.szczodrzynski.edziennik.utils.Utils.d
@ -76,7 +77,7 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
}
override fun getAttachment(messageId: Long, attachmentId: Long, attachmentName: String) {
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
}

View File

@ -125,6 +125,7 @@ class MessageFragment : Fragment(), CoroutineScope {
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onMessageGetEvent(event: MessageGetEvent) {
EventBus.getDefault().removeStickyEvent(event)
// TODO remove this: message = event.message
showMessage()
}
@ -197,6 +198,7 @@ class MessageFragment : Fragment(), CoroutineScope {
private fun showAttachments() {
if (message.attachmentIds != null) {
val insertPoint = b.attachments
insertPoint.removeAllViews()
val chipLayoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
chipLayoutParams.setMargins(0, Utils.dpToPx(8), 0, Utils.dpToPx(8))
@ -285,7 +287,7 @@ class MessageFragment : Fragment(), CoroutineScope {
EdziennikTask.attachmentGet(
App.profileId,
attachment.messageId,
message,
attachment.attachmentId,
attachment.attachmentName
).enqueue(activity)