Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add use case to download assets by its asset key/id (AR-1094) #243

Merged
merged 74 commits into from
Mar 9, 2022
Merged
Changes from 66 commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
895440f
feat: create basic structure to update self user, calling api endpoint
yamilmedina Feb 16, 2022
5817033
Merge branch 'develop' into feat/linkuploadedasset-to-profile-pic
yamilmedina Feb 17, 2022
f05edb6
feat: map user data from api and persist into db entity
yamilmedina Feb 17, 2022
62b2d73
feat: uploaded data and linking to user self
yamilmedina Feb 17, 2022
114b3d8
chore: fix tests and configure primiteve adapter for native sq to kot…
yamilmedina Feb 18, 2022
5999589
Merge branch 'develop' into feat/linkuploadedasset-to-profile-pic
yamilmedina Feb 18, 2022
4f2f5c1
chore: fix tests for uploadavatar case, mocks
yamilmedina Feb 18, 2022
bf2443d
refactor: rename of user on persistence module to userentity agreed s…
yamilmedina Feb 18, 2022
a805e19
Merge branch 'develop' into feat/linkuploadedasset-to-profile-pic
yamilmedina Feb 21, 2022
cb0061e
fix: persiste userentity on remote update success
yamilmedina Feb 21, 2022
eb4e1e2
fix: add comment about not mapped field yet
yamilmedina Feb 21, 2022
d8dfee2
fix: wip model asset entity
yamilmedina Feb 22, 2022
3c4ee6e
Merge branch 'develop' into feat/add_assets_table
yamilmedina Feb 22, 2022
3ea1d51
feat: add mapping and dao to persist an asset
yamilmedina Feb 22, 2022
46dcaee
feat: map and store the uploaded asset into the table
yamilmedina Feb 23, 2022
86214d6
Merge branch 'develop' into feat/add_assets_table
yamilmedina Feb 23, 2022
3c1f08d
test: fix broken test
yamilmedina Feb 23, 2022
8a612b0
feat: add mapping for FKs and define strategy to fetch/download pics
yamilmedina Feb 23, 2022
f1d401a
Merge branch 'develop' into feat/add_assets_table
yamilmedina Feb 24, 2022
9004452
feat: add logic to persist assets from users response and also after …
yamilmedina Feb 24, 2022
6374628
feat: change strategy for fk on users, assets
yamilmedina Feb 25, 2022
3cfe5af
Merge branch 'develop' into feat/add_assets_table
yamilmedina Feb 25, 2022
434d520
test: fix tests as vargars was causing issues with mockative
yamilmedina Feb 25, 2022
0301bc9
chore: add todo task to be refined later
yamilmedina Feb 25, 2022
6362fc6
chore: fix reference on cli proj
yamilmedina Feb 25, 2022
e90f5f7
chore: fix tests on network module
yamilmedina Feb 25, 2022
b331b2b
feat: add usecase base call to download a public asset
yamilmedina Feb 25, 2022
f0d7aba
feature: add map of pictures connections users
yamilmedina Feb 28, 2022
07f6afc
feature: refactor map func
yamilmedina Feb 28, 2022
ae51253
feature: add map of pictures connections users
yamilmedina Feb 28, 2022
b166680
feature: refactor map func
yamilmedina Feb 28, 2022
821217f
Merge branch 'feat/add_assets_table' into feat/add_usecase_to_downloa…
yamilmedina Feb 28, 2022
c32fbf3
feature: rename asset usecase for public assets
yamilmedina Feb 28, 2022
f32a7c4
test: fix broken test
yamilmedina Feb 28, 2022
71c0801
Merge branch 'feat/add_assets_table' into feat/add_usecase_to_downloa…
yamilmedina Feb 28, 2022
1da422c
Merge branch 'develop' into feat/add_assets_table
yamilmedina Feb 28, 2022
a5d7f9d
fix: refactor code to use wrapApiRequest
yamilmedina Feb 28, 2022
4dcc361
fix: fix cli module ref
yamilmedina Feb 28, 2022
48f9100
Merge branch 'feat/add_assets_table' into feat/add_usecase_to_downloa…
yamilmedina Feb 28, 2022
945a68c
chore: add test coverage for assetsrepository
yamilmedina Feb 28, 2022
5e85fa9
chore: refactor naming of functions and add func to persist asset data
yamilmedina Feb 28, 2022
7e270f5
chore: address pr comments, remove md5 field and calulate it
yamilmedina Mar 1, 2022
d9e2b27
chore: address pr comments, remove field from db
yamilmedina Mar 1, 2022
18e5d00
Merge branch 'develop' into feat/add_assets_table
yamilmedina Mar 1, 2022
cf1eb0b
chore: reference on imports fixed
yamilmedina Mar 1, 2022
e182f4e
chore: fix test reference
yamilmedina Mar 1, 2022
3e05fce
Merge branch 'develop' into feat/add_assets_table
yamilmedina Mar 1, 2022
5984f70
Merge branch 'feat/add_assets_table' into feat/add_usecase_to_downloa…
yamilmedina Mar 1, 2022
0e4da35
chore: fix test reference
yamilmedina Mar 1, 2022
7cd7299
Merge branch 'feat/add_assets_table' into feat/add_usecase_to_downloa…
yamilmedina Mar 1, 2022
a46a7ca
chore: add tests for assetrepository with new structure
yamilmedina Mar 1, 2022
c4fac55
Merge branch 'develop' into feat/add_assets_table
yamilmedina Mar 2, 2022
2a3c276
Merge branch 'feat/add_assets_table' into feat/add_usecase_to_downloa…
yamilmedina Mar 2, 2022
37afc53
chore: fix returns value from usecase
yamilmedina Mar 3, 2022
d40b767
Merge branch 'develop' into feat/add_assets_table
yamilmedina Mar 3, 2022
316f8b6
Merge branch 'feat/add_assets_table' into feat/add_usecase_to_downloa…
yamilmedina Mar 3, 2022
0889ac9
chore: refactor asset table to have minimal fields, metadata will be …
yamilmedina Mar 3, 2022
412633f
chore: rename mappers functions and todo added
yamilmedina Mar 3, 2022
f541584
Merge branch 'feat/add_assets_table' into feat/add_usecase_to_downloa…
yamilmedina Mar 3, 2022
eee3ed0
chore: refactor, apply changes to sync contacts pics on one step donw…
yamilmedina Mar 3, 2022
58fd6ff
chore: make rawdata notnullable
yamilmedina Mar 4, 2022
b54c784
Merge branch 'feat/add_assets_table' into feat/add_usecase_to_downloa…
yamilmedina Mar 4, 2022
05c850a
chore: change input and return of usecase to not expose either
yamilmedina Mar 4, 2022
1e16650
chore: fix pr comments, applying better naming
yamilmedina Mar 4, 2022
901dcc9
chore: fix test ref
yamilmedina Mar 4, 2022
c8983c3
Merge branch 'feat/add_assets_table' into feat/add_usecase_to_downloa…
yamilmedina Mar 4, 2022
b53a88a
chore: fix broken test
yamilmedina Mar 4, 2022
6c67bca
chore: remove hard ref FK on users/assets to allow sync contacts on d…
yamilmedina Mar 4, 2022
dc256bb
chore: add cause to failure result on usecases for avatar
yamilmedina Mar 4, 2022
84c7f1a
Merge branch 'develop' into feat/add_usecase_to_download_assets
yamilmedina Mar 4, 2022
9f60306
Merge branch 'develop' into feat/add_usecase_to_download_assets
yamilmedina Mar 8, 2022
54a2cda
fix: returns uploaded assetid in usecase
yamilmedina Mar 8, 2022
a0c4b75
enhancement: adds documentation to public interfaces
yamilmedina Mar 8, 2022
c8fd263
Merge branch 'develop' into feat/add_usecase_to_download_assets
yamilmedina Mar 9, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,45 +1,64 @@
package com.wire.kalium.presentation

import android.graphics.BitmapFactory
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.material.Divider
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.unit.dp
import androidx.lifecycle.lifecycleScope
import com.wire.kalium.KaliumApplication
import com.wire.kalium.logic.CoreLogic
import com.wire.kalium.logic.configuration.ServerConfig
import com.wire.kalium.logic.data.conversation.Conversation
import com.wire.kalium.logic.data.user.SelfUser
import com.wire.kalium.logic.feature.asset.PublicAssetResult
import com.wire.kalium.logic.feature.auth.AuthSession
import com.wire.kalium.logic.feature.auth.AuthenticationResult
import com.wire.kalium.logic.feature.auth.AuthenticationScope
import kotlinx.coroutines.flow.first

class MainActivity : ComponentActivity() {

val serverConfig: ServerConfig by lazy { ServerConfig.DEFAULT }
private val serverConfig: ServerConfig by lazy { ServerConfig.DEFAULT }

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

loginAndFetchConverationList((application as KaliumApplication).coreLogic)
loginAndFetchConversationList((application as KaliumApplication).coreLogic)
}

fun loginAndFetchConverationList(coreLogic: CoreLogic) = lifecycleScope.launchWhenCreated {
private fun loginAndFetchConversationList(coreLogic: CoreLogic) = lifecycleScope.launchWhenCreated {
login(coreLogic.getAuthenticationScope())?.let {
val session = coreLogic.getSessionScope(it)
val conversations = session.conversations.getConversations().first()

// Uploading image code
// val imageContent = applicationContext.assets.open("moon1.jpg").readBytes()
// session.users.uploadUserAvatar("image/jpg", imageContent)

val selfUser = session.users.getSelfUser().first()

val avatarAsset = when (val publicAsset = session.users.getPublicAsset(selfUser.previewPicture.toString())) {
is PublicAssetResult.Success -> publicAsset.asset
else -> null
}

setContent {
MainLayout(conversations, selfUser)
MainLayout(conversations, selfUser, avatarAsset)
}
}
}

suspend fun login(authenticationScope: AuthenticationScope): AuthSession? {
private suspend fun login(authenticationScope: AuthenticationScope): AuthSession? {
val result = authenticationScope.login("jacob.persson+summer1@wire.com", "hepphepp", false, serverConfig)

if (result !is AuthenticationResult.Success) {
@@ -54,11 +73,26 @@ class MainActivity : ComponentActivity() {
}

@Composable
fun MainLayout(conversations: List<Conversation>, selfUser: SelfUser) {
fun MainLayout(conversations: List<Conversation>, selfUser: SelfUser, avatarAsset: ByteArray?) {
Column {
Text("Conversation count:")
Text("${conversations.size}")
Text("SelfUser:")
Text("$selfUser")

Divider(
modifier = Modifier.fillMaxWidth(),
thickness = 0.5.dp
)

Text(text = "Avatar picture:")

avatarAsset?.let { byteArray ->
Image(
bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)?.asImageBitmap()!!,
contentDescription = "",
modifier = Modifier.size(300.dp)
)
}
}
}
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ import com.wire.kalium.logic.configuration.ServerConfigMapper
import com.wire.kalium.logic.configuration.ServerConfigMapperImpl
import com.wire.kalium.network.AuthenticatedNetworkContainer
import com.wire.kalium.network.LoginNetworkContainer
import com.wire.kalium.network.api.model.AssetMetadataRequest
import com.wire.kalium.network.api.asset.AssetMetadataRequest
import com.wire.kalium.network.api.model.AssetRetentionType
import com.wire.kalium.network.api.user.login.LoginApi
import com.wire.kalium.network.tools.BackendConfig
@@ -34,7 +34,7 @@ class ConversationsApplication : CliktCommand() {
println("There was an error on the login :( check the credentials and the internet connection and try again please")
} else {
val sessionData = loginResult.value
//TODO: Get them 🍪 refresh token
// TODO: Get them 🍪 refresh token
val networkModule = AuthenticatedNetworkContainer(sessionDTO = sessionData, backendConfig = backendConfig)
val conversationsResponse = networkModule.conversationApi.conversationsByBatch(null, 100)

Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.wire.kalium.logic.data.asset

import com.wire.kalium.cryptography.utils.calcMd5

data class UploadedAssetId(val key: String)

/**
@@ -15,8 +13,6 @@ data class UploadAssetData(
val retentionType: RetentionType
) {

var md5: String = calcMd5(data)

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
@@ -27,7 +23,6 @@ data class UploadAssetData(
if (mimeType != other.mimeType) return false
if (isPublic != other.isPublic) return false
if (retentionType != other.retentionType) return false
if (md5 != other.md5) return false

return true
}
@@ -37,7 +32,6 @@ data class UploadAssetData(
result = 31 * result + mimeType.hashCode()
result = 31 * result + isPublic.hashCode()
result = 31 * result + retentionType.hashCode()
result = 31 * result + md5.hashCode()
return result
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package com.wire.kalium.logic.data.asset

import com.wire.kalium.network.api.model.AssetMetadataRequest
import com.wire.kalium.network.api.model.AssetResponse
import com.wire.kalium.cryptography.utils.calcMd5
import com.wire.kalium.network.api.asset.AssetMetadataRequest
import com.wire.kalium.network.api.asset.AssetResponse
import com.wire.kalium.network.api.model.AssetRetentionType
import com.wire.kalium.persistence.dao.asset.AssetEntity
import kotlinx.datetime.Clock

interface AssetMapper {
fun toMetadataApiModel(uploadAssetMetadata: UploadAssetData): AssetMetadataRequest
fun toDomainModel(asset: AssetResponse): UploadedAssetId
fun fromApiUploadResponseToDomainModel(asset: AssetResponse): UploadedAssetId
fun fromUploadedAssetToDaoModel(uploadAssetData: UploadAssetData, uploadedAssetResponse: AssetResponse): AssetEntity
fun fromUserAssetToDaoModel(assetKey: String, data: ByteArray): AssetEntity
}

class AssetMapperImpl : AssetMapper {
@@ -15,9 +20,30 @@ class AssetMapperImpl : AssetMapper {
uploadAssetMetadata.mimeType.name,
uploadAssetMetadata.isPublic,
AssetRetentionType.valueOf(uploadAssetMetadata.retentionType.name),
uploadAssetMetadata.md5
calcMd5(uploadAssetMetadata.data)
)
}

override fun toDomainModel(asset: AssetResponse) = UploadedAssetId(asset.key)
override fun fromApiUploadResponseToDomainModel(asset: AssetResponse) =
UploadedAssetId(asset.key)

override fun fromUploadedAssetToDaoModel(uploadAssetData: UploadAssetData, uploadedAssetResponse: AssetResponse): AssetEntity {
return AssetEntity(
key = uploadedAssetResponse.key,
domain = uploadedAssetResponse.domain,
mimeType = uploadAssetData.mimeType.name,
rawData = uploadAssetData.data,
downloadedDate = Clock.System.now().toEpochMilliseconds()
)
}

override fun fromUserAssetToDaoModel(assetKey: String, data: ByteArray): AssetEntity {
return AssetEntity(
key = assetKey,
domain = "", // is it possible to know this on contacts sync avatars ?
mimeType = "",
rawData = data,
downloadedDate = Clock.System.now().toEpochMilliseconds()
)
}
}
Original file line number Diff line number Diff line change
@@ -2,25 +2,55 @@ package com.wire.kalium.logic.data.asset

import com.wire.kalium.logic.CoreFailure
import com.wire.kalium.logic.NetworkFailure
import com.wire.kalium.logic.data.user.UserAssetId
import com.wire.kalium.logic.functional.Either
import com.wire.kalium.logic.functional.map
import com.wire.kalium.logic.functional.suspending
import com.wire.kalium.logic.wrapApiRequest
import com.wire.kalium.network.api.asset.AssetApi
import com.wire.kalium.persistence.dao.asset.AssetDAO
import kotlinx.coroutines.flow.firstOrNull

interface AssetRepository {
suspend fun uploadPublicAsset(uploadAssetData: UploadAssetData): Either<CoreFailure, UploadedAssetId>
suspend fun uploadAndPersistPublicAsset(uploadAssetData: UploadAssetData): Either<CoreFailure, UploadedAssetId>
suspend fun downloadPublicAsset(assetKey: String): Either<CoreFailure, ByteArray>
suspend fun downloadUsersPictureAssets(assetId: List<UserAssetId?>): Either<CoreFailure, Unit>
}

internal class AssetDataSource(
private val assetApi: AssetApi,
private val assetMapper: AssetMapper
private val assetMapper: AssetMapper,
private val assetDao: AssetDAO
) : AssetRepository {

override suspend fun uploadPublicAsset(uploadAssetData: UploadAssetData): Either<NetworkFailure, UploadedAssetId> =
wrapApiRequest {
assetMapper.toMetadataApiModel(uploadAssetData).let { metaData ->
assetApi.uploadAsset(metaData, uploadAssetData.data)
override suspend fun uploadAndPersistPublicAsset(uploadAssetData: UploadAssetData): Either<NetworkFailure, UploadedAssetId> =
suspending {
wrapApiRequest {
assetMapper.toMetadataApiModel(uploadAssetData).let { metaData ->
assetApi.uploadAsset(metaData, uploadAssetData.data)
}
}.map { assetResponse ->
val assetEntity = assetMapper.fromUploadedAssetToDaoModel(uploadAssetData, assetResponse)
assetDao.insertAsset(assetEntity)
assetMapper.fromApiUploadResponseToDomainModel(assetResponse)
}
}.map { assetMapper.toDomainModel(it) }
}

override suspend fun downloadPublicAsset(assetKey: String): Either<CoreFailure, ByteArray> = suspending {
val persistedAsset = assetDao.getAssetByKey(assetKey).firstOrNull()
if (persistedAsset?.rawData != null) return@suspending Either.Right(persistedAsset.rawData!!)

wrapApiRequest {
assetApi.downloadAsset(assetKey, null)
}.map { assetData ->
assetDao.insertAsset(assetMapper.fromUserAssetToDaoModel(assetKey, assetData))
assetData
}
}

override suspend fun downloadUsersPictureAssets(assetId: List<UserAssetId?>): Either<CoreFailure, Unit> = suspending {
assetId.filterNotNull().forEach {
downloadPublicAsset(it)
}
return@suspending Either.Right(Unit)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.wire.kalium.logic.data.user

import com.wire.kalium.logic.data.id.IdMapper
import com.wire.kalium.network.api.asset.ImageSize
import com.wire.kalium.network.api.asset.AvatarAssetDTO
import com.wire.kalium.network.api.asset.getCompleteAssetOrNull
import com.wire.kalium.network.api.asset.getPreviewAssetOrNull
import com.wire.kalium.network.api.user.details.UserDetailsResponse
import com.wire.kalium.network.api.user.self.ImageSize
import com.wire.kalium.network.api.user.self.SelfUserInfoResponse
import com.wire.kalium.network.api.user.self.UserAssetRequest
import com.wire.kalium.network.api.user.self.UserUpdateRequest
import com.wire.kalium.persistence.dao.UserEntity
import com.wire.kalium.persistence.dao.UserId as UserIdEntity
@@ -14,6 +16,7 @@ interface UserMapper {
fun fromApiModelToDaoModel(userDetailsResponse: UserDetailsResponse): UserEntity
fun fromApiModelToDaoModel(selfUserInfoResponse: SelfUserInfoResponse): UserEntity
fun fromDaoModel(user: UserEntity): SelfUser

/**
* Maps the user data to be updated. if the parameters [newName] [newAccent] [newAssetId] are nulls,
* it indicates that not updation should be made.
@@ -36,24 +39,37 @@ internal class UserMapperImpl(private val idMapper: IdMapper) : UserMapper {
selfUserInfoResponse.phone,
selfUserInfoResponse.accentId,
selfUserInfoResponse.team,
emptyList()
selfUserInfoResponse.assets.getPreviewAssetOrNull()?.key,
selfUserInfoResponse.assets.getCompleteAssetOrNull()?.key
)
}

override fun fromApiModelToDaoModel(userDetailsResponse: UserDetailsResponse): UserEntity {
return UserEntity(
idMapper.fromApiToDao(userDetailsResponse.id),
userDetailsResponse.name,
userDetailsResponse.handle,
null,
null,
userDetailsResponse.accentId,
null
id = idMapper.fromApiToDao(userDetailsResponse.id),
name = userDetailsResponse.name,
handle = userDetailsResponse.handle,
email = null,
phone = null,
accentId = userDetailsResponse.accentId,
team = userDetailsResponse.team,
previewAssetId = userDetailsResponse.assets.getPreviewAssetOrNull()?.key,
completeAssetId = userDetailsResponse.assets.getCompleteAssetOrNull()?.key
)
}

override fun fromDaoModel(user: UserEntity) =
SelfUser(idMapper.fromDaoModel(user.id), user.name, user.handle, user.email, user.phone, user.accentId, user.team, emptyList())
SelfUser(
idMapper.fromDaoModel(user.id),
user.name,
user.handle,
user.email,
user.phone,
user.accentId,
user.team,
user.previewAssetId,
user.completeAssetId
)

override fun fromModelToUpdateApiModel(
user: SelfUser,
@@ -68,8 +84,8 @@ internal class UserMapperImpl(private val idMapper: IdMapper) : UserMapper {
accentId = newAccent,
assets = if (newAssetId != null) {
listOf(
UserAssetRequest(newAssetId, ImageSize.Complete),
UserAssetRequest(newAssetId, ImageSize.Preview)
AvatarAssetDTO(newAssetId, ImageSize.Complete),
AvatarAssetDTO(newAssetId, ImageSize.Preview)
)
} else {
null
@@ -85,7 +101,9 @@ internal class UserMapperImpl(private val idMapper: IdMapper) : UserMapper {
email = user.email,
phone = user.phone,
accentId = updateRequest.accentId ?: user.accentId,
team = user.team
team = user.team,
previewAssetId = updateRequest.assets?.getPreviewAssetOrNull()?.key,
completeAssetId = updateRequest.assets?.getCompleteAssetOrNull()?.key
)
}

@@ -97,7 +115,9 @@ internal class UserMapperImpl(private val idMapper: IdMapper) : UserMapper {
selfUserInfoResponse.email,
selfUserInfoResponse.phone,
selfUserInfoResponse.accentId,
selfUserInfoResponse.team
selfUserInfoResponse.team,
selfUserInfoResponse.assets.getPreviewAssetOrNull()?.key,
selfUserInfoResponse.assets.getCompleteAssetOrNull()?.key
)
}

Loading